Methods Summary |
---|
public void | addDocumentListener(javax.swing.event.DocumentListener listener)Adds a document listener for notification of any changes.
listenerList.add(DocumentListener.class, listener);
|
public void | addUndoableEditListener(javax.swing.event.UndoableEditListener listener)Adds an undo listener for notification of any changes.
Undo/Redo operations performed on the UndoableEdit
will cause the appropriate DocumentEvent to be fired to keep
the view(s) in sync with the model.
listenerList.add(UndoableEditListener.class, listener);
|
private byte[] | calculateBidiLevels(int firstPStart, int lastPEnd)Calculate the levels array for a range of paragraphs.
byte levels[] = new byte[ lastPEnd - firstPStart ];
int levelsEnd = 0;
Boolean defaultDirection = null;
Object d = getProperty(TextAttribute.RUN_DIRECTION);
if (d instanceof Boolean) {
defaultDirection = (Boolean) d;
}
// For each paragraph in the given range of paragraphs, get its
// levels array and add it to the levels array for the entire span.
for(int o=firstPStart; o<lastPEnd; ) {
Element p = getParagraphElement( o );
int pStart = p.getStartOffset();
int pEnd = p.getEndOffset();
// default run direction for the paragraph. This will be
// null if there is no direction override specified (i.e.
// the direction will be determined from the content).
Boolean direction = defaultDirection;
d = p.getAttributes().getAttribute(TextAttribute.RUN_DIRECTION);
if (d instanceof Boolean) {
direction = (Boolean) d;
}
//System.out.println("updateBidi: paragraph start = " + pStart + " paragraph end = " + pEnd);
// Create a Bidi over this paragraph then get the level
// array.
Segment seg = SegmentCache.getSharedSegment();
try {
getText(pStart, pEnd-pStart, seg);
} catch (BadLocationException e ) {
throw new Error("Internal error: " + e.toString());
}
// REMIND(bcb) we should really be using a Segment here.
Bidi bidiAnalyzer;
int bidiflag = Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT;
if (direction != null) {
if (TextAttribute.RUN_DIRECTION_LTR.equals(direction)) {
bidiflag = Bidi.DIRECTION_LEFT_TO_RIGHT;
} else {
bidiflag = Bidi.DIRECTION_RIGHT_TO_LEFT;
}
}
bidiAnalyzer = new Bidi(seg.array, seg.offset, null, 0, seg.count,
bidiflag);
BidiUtils.getLevels(bidiAnalyzer, levels, levelsEnd);
levelsEnd += bidiAnalyzer.getLength();
o = p.getEndOffset();
SegmentCache.releaseSharedSegment(seg);
}
// REMIND(bcb) remove this code when debugging is done.
if( levelsEnd != levels.length )
throw new Error("levelsEnd assertion failed.");
return levels;
|
protected javax.swing.text.Element | createBranchElement(javax.swing.text.Element parent, javax.swing.text.AttributeSet a)Creates a document branch element, that can contain other elements.
return new BranchElement(parent, a);
|
protected javax.swing.text.Element | createLeafElement(javax.swing.text.Element parent, javax.swing.text.AttributeSet a, int p0, int p1)Creates a document leaf element.
Hook through which elements are created to represent the
document structure. Because this implementation keeps
structure and content separate, elements grow automatically
when content is extended so splits of existing elements
follow. The document itself gets to decide how to generate
elements to give flexibility in the type of elements used.
return new LeafElement(parent, a, p0, p1);
|
public synchronized javax.swing.text.Position | createPosition(int offs)Returns a position that will track change as the document
is altered.
This method is thread safe, although most Swing methods
are not. Please see
How
to Use Threads for more information.
return data.createPosition(offs);
|
public void | dump(java.io.PrintStream out)Gives a diagnostic dump.
Element root = getDefaultRootElement();
if (root instanceof AbstractElement) {
((AbstractElement)root).dump(out, 0);
}
bidiRoot.dump(out,0);
|
protected void | fireChangedUpdate(javax.swing.event.DocumentEvent e)Notifies all listeners that have registered interest for
notification on this event type. The event instance
is lazily created using the parameters passed into
the fire method.
notifyingListeners = true;
try {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==DocumentListener.class) {
// Lazily create the event:
// if (e == null)
// e = new ListSelectionEvent(this, firstIndex, lastIndex);
((DocumentListener)listeners[i+1]).changedUpdate(e);
}
}
} finally {
notifyingListeners = false;
}
|
protected void | fireInsertUpdate(javax.swing.event.DocumentEvent e)Notifies all listeners that have registered interest for
notification on this event type. The event instance
is lazily created using the parameters passed into
the fire method.
notifyingListeners = true;
try {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==DocumentListener.class) {
// Lazily create the event:
// if (e == null)
// e = new ListSelectionEvent(this, firstIndex, lastIndex);
((DocumentListener)listeners[i+1]).insertUpdate(e);
}
}
} finally {
notifyingListeners = false;
}
|
protected void | fireRemoveUpdate(javax.swing.event.DocumentEvent e)Notifies all listeners that have registered interest for
notification on this event type. The event instance
is lazily created using the parameters passed into
the fire method.
notifyingListeners = true;
try {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==DocumentListener.class) {
// Lazily create the event:
// if (e == null)
// e = new ListSelectionEvent(this, firstIndex, lastIndex);
((DocumentListener)listeners[i+1]).removeUpdate(e);
}
}
} finally {
notifyingListeners = false;
}
|
protected void | fireUndoableEditUpdate(javax.swing.event.UndoableEditEvent e)Notifies all listeners that have registered interest for
notification on this event type. The event instance
is lazily created using the parameters passed into
the fire method.
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==UndoableEditListener.class) {
// Lazily create the event:
// if (e == null)
// e = new ListSelectionEvent(this, firstIndex, lastIndex);
((UndoableEditListener)listeners[i+1]).undoableEditHappened(e);
}
}
|
public int | getAsynchronousLoadPriority()Gets the asynchronous loading priority. If less than zero,
the document should not be loaded asynchronously.
Integer loadPriority = (Integer)
getProperty(AbstractDocument.AsyncLoadPriority);
if (loadPriority != null) {
return loadPriority.intValue();
}
return -1;
|
protected final javax.swing.text.AbstractDocument$AttributeContext | getAttributeContext()Fetches the context for managing attributes. This
method effectively establishes the strategy used
for compressing AttributeSet information.
return context;
|
public javax.swing.text.Element | getBidiRootElement()Returns the root element of the bidirectional structure for this
document. Its children represent character runs with a given
Unicode bidi level.
return bidiRoot;
|
protected final javax.swing.text.AbstractDocument$Content | getContent()Gets the content for the document.
return data;
|
protected final synchronized java.lang.Thread | getCurrentWriter()Fetches the current writing thread if there is one.
This can be used to distinguish whether a method is
being called as part of an existing modification or
if a lock needs to be acquired and a new transaction
started.
return currWriter;
|
public abstract javax.swing.text.Element | getDefaultRootElement()Returns the root element that views should be based upon
unless some other mechanism for assigning views to element
structures is provided.
|
public javax.swing.text.DocumentFilter | getDocumentFilter()Returns the DocumentFilter that is responsible for
filtering of insertion/removal. A null return value
implies no filtering is to occur.
return documentFilter;
|
public javax.swing.event.DocumentListener[] | getDocumentListeners()Returns an array of all the document listeners
registered on this document.
return (DocumentListener[])listenerList.getListeners(
DocumentListener.class);
|
public java.util.Dictionary | getDocumentProperties()Supports managing a set of properties. Callers
can use the documentProperties dictionary
to annotate the document with document-wide properties.
if (documentProperties == null) {
documentProperties = new Hashtable(2);
}
return documentProperties;
|
public final javax.swing.text.Position | getEndPosition()Returns a position that represents the end of the document. The
position returned can be counted on to track change and stay
located at the end of the document.
Position p;
try {
p = createPosition(data.length());
} catch (BadLocationException bl) {
p = null;
}
return p;
|
private javax.swing.text.DocumentFilter$FilterBypass | getFilterBypass()Returns the FilterBypass . This will create one if one
does not yet exist.
if (filterBypass == null) {
filterBypass = new DefaultFilterBypass();
}
return filterBypass;
|
public int | getLength()Returns the length of the data. This is the number of
characters of content that represents the users data.
return data.length() - 1;
|
public T[] | getListeners(java.lang.Class listenerType)Returns an array of all the objects currently registered
as FooListener s
upon this document.
FooListener s are registered using the
addFooListener method.
You can specify the listenerType argument
with a class literal, such as
FooListener.class .
For example, you can query a
document d
for its document listeners with the following code:
DocumentListener[] mls = (DocumentListener[])(d.getListeners(DocumentListener.class));
If no such listeners exist, this method returns an empty array.
return listenerList.getListeners(listenerType);
|
public abstract javax.swing.text.Element | getParagraphElement(int pos)Get the paragraph element containing the given position. Sub-classes
must define for themselves what exactly constitutes a paragraph. They
should keep in mind however that a paragraph should at least be the
unit of text over which to run the Unicode bidirectional algorithm.
|
public final java.lang.Object | getProperty(java.lang.Object key)A convenience method for looking up a property value. It is
equivalent to:
getDocumentProperties().get(key);
return getDocumentProperties().get(key);
|
public javax.swing.text.Element[] | getRootElements()Gets all root elements defined. Typically, there
will only be one so the default implementation
is to return the default root element.
Element[] elems = new Element[2];
elems[0] = getDefaultRootElement();
elems[1] = getBidiRootElement();
return elems;
|
public final javax.swing.text.Position | getStartPosition()Returns a position that represents the start of the document. The
position returned can be counted on to track change and stay
located at the beginning of the document.
Position p;
try {
p = createPosition(0);
} catch (BadLocationException bl) {
p = null;
}
return p;
|
public java.lang.String | getText(int offset, int length)Gets a sequence of text from the document.
if (length < 0) {
throw new BadLocationException("Length must be positive", length);
}
String str = data.getString(offset, length);
return str;
|
public void | getText(int offset, int length, javax.swing.text.Segment txt)Fetches the text contained within the given portion
of the document.
If the partialReturn property on the txt parameter is false, the
data returned in the Segment will be the entire length requested and
may or may not be a copy depending upon how the data was stored.
If the partialReturn property is true, only the amount of text that
can be returned without creating a copy is returned. Using partial
returns will give better performance for situations where large
parts of the document are being scanned. The following is an example
of using the partial return to access the entire document:
int nleft = doc.getDocumentLength();
Segment text = new Segment();
int offs = 0;
text.setPartialReturn(true);
while (nleft > 0) {
doc.getText(offs, nleft, text);
// do something with text
nleft -= text.count;
offs += text.count;
}
if (length < 0) {
throw new BadLocationException("Length must be positive", length);
}
data.getChars(offset, length, txt);
|
public javax.swing.event.UndoableEditListener[] | getUndoableEditListeners()Returns an array of all the undoable edit listeners
registered on this document.
return (UndoableEditListener[])listenerList.getListeners(
UndoableEditListener.class);
|
void | handleInsertString(int offs, java.lang.String str, javax.swing.text.AttributeSet a)Performs the actual work of inserting the text; it is assumed the
caller has obtained a write lock before invoking this.
if ((str == null) || (str.length() == 0)) {
return;
}
UndoableEdit u = data.insertString(offs, str);
DefaultDocumentEvent e =
new DefaultDocumentEvent(offs, str.length(), DocumentEvent.EventType.INSERT);
if (u != null) {
e.addEdit(u);
}
// see if complex glyph layout support is needed
if( getProperty(I18NProperty).equals( Boolean.FALSE ) ) {
// if a default direction of right-to-left has been specified,
// we want complex layout even if the text is all left to right.
Object d = getProperty(TextAttribute.RUN_DIRECTION);
if ((d != null) && (d.equals(TextAttribute.RUN_DIRECTION_RTL))) {
putProperty( I18NProperty, Boolean.TRUE);
} else {
char[] chars = str.toCharArray();
if (SwingUtilities2.isComplexLayout(chars, 0, chars.length)) {
putProperty( I18NProperty, Boolean.TRUE);
}
}
}
insertUpdate(e, a);
// Mark the edit as done.
e.end();
fireInsertUpdate(e);
// only fire undo if Content implementation supports it
// undo for the composed text is not supported for now
if (u != null &&
(a == null || !a.isDefined(StyleConstants.ComposedTextAttribute))) {
fireUndoableEditUpdate(new UndoableEditEvent(this, e));
}
|
void | handleRemove(int offs, int len)Performs the actual work of the remove. It is assumed the caller
will have obtained a writeLock before invoking this.
if (len > 0) {
if (offs < 0 || (offs + len) > getLength()) {
throw new BadLocationException("Invalid remove",
getLength() + 1);
}
DefaultDocumentEvent chng =
new DefaultDocumentEvent(offs, len, DocumentEvent.EventType.REMOVE);
boolean isComposedTextElement = false;
// Check whether the position of interest is the composed text
isComposedTextElement = Utilities.isComposedTextElement(this, offs);
removeUpdate(chng);
UndoableEdit u = data.remove(offs, len);
if (u != null) {
chng.addEdit(u);
}
postRemoveUpdate(chng);
// Mark the edit as done.
chng.end();
fireRemoveUpdate(chng);
// only fire undo if Content implementation supports it
// undo for the composed text is not supported for now
if ((u != null) && !isComposedTextElement) {
fireUndoableEditUpdate(new UndoableEditEvent(this, chng));
}
}
|
public void | insertString(int offs, java.lang.String str, javax.swing.text.AttributeSet a)Inserts some content into the document.
Inserting content causes a write lock to be held while the
actual changes are taking place, followed by notification
to the observers on the thread that grabbed the write lock.
This method is thread safe, although most Swing methods
are not. Please see
How
to Use Threads for more information.
if ((str == null) || (str.length() == 0)) {
return;
}
DocumentFilter filter = getDocumentFilter();
writeLock();
try {
if (filter != null) {
filter.insertString(getFilterBypass(), offs, str, a);
}
else {
handleInsertString(offs, str, a);
}
} finally {
writeUnlock();
}
|
protected void | insertUpdate(javax.swing.text.AbstractDocument$DefaultDocumentEvent chng, javax.swing.text.AttributeSet attr)Updates document structure as a result of text insertion. This
will happen within a write lock. If a subclass of
this class reimplements this method, it should delegate to the
superclass as well.
if( getProperty(I18NProperty).equals( Boolean.TRUE ) )
updateBidi( chng );
// Check if a multi byte is encountered in the inserted text.
if (chng.type == DocumentEvent.EventType.INSERT &&
chng.getLength() > 0 &&
!Boolean.TRUE.equals(getProperty(MultiByteProperty))) {
Segment segment = SegmentCache.getSharedSegment();
try {
getText(chng.getOffset(), chng.getLength(), segment);
segment.first();
do {
if ((int)segment.current() > 255) {
putProperty(MultiByteProperty, Boolean.TRUE);
break;
}
} while (segment.next() != Segment.DONE);
} catch (BadLocationException ble) {
// Should never happen
}
SegmentCache.releaseSharedSegment(segment);
}
|
boolean | isLeftToRight(int p0, int p1)Returns true if the text in the range p0 to
p1 is left to right.
if(!getProperty(I18NProperty).equals(Boolean.TRUE)) {
return true;
}
Element bidiRoot = getBidiRootElement();
int index = bidiRoot.getElementIndex(p0);
Element bidiElem = bidiRoot.getElement(index);
if(bidiElem.getEndOffset() >= p1) {
AttributeSet bidiAttrs = bidiElem.getAttributes();
return ((StyleConstants.getBidiLevel(bidiAttrs) % 2) == 0);
}
return true;
|
protected void | postRemoveUpdate(javax.swing.text.AbstractDocument$DefaultDocumentEvent chng)Updates any document structure as a result of text removal. This
method is called after the text has been removed from the Content.
This will happen within a write lock. If a subclass
of this class reimplements this method, it should delegate to the
superclass as well.
if( getProperty(I18NProperty).equals( Boolean.TRUE ) )
updateBidi( chng );
|
public final void | putProperty(java.lang.Object key, java.lang.Object value)A convenience method for storing up a property value. It is
equivalent to:
getDocumentProperties().put(key, value);
If value is null this method will
remove the property.
if (value != null) {
getDocumentProperties().put(key, value);
} else {
getDocumentProperties().remove(key);
}
if( key == TextAttribute.RUN_DIRECTION
&& Boolean.TRUE.equals(getProperty(I18NProperty)) )
{
//REMIND - this needs to flip on the i18n property if run dir
//is rtl and the i18n property is not already on.
writeLock();
try {
DefaultDocumentEvent e
= new DefaultDocumentEvent(0, getLength(),
DocumentEvent.EventType.INSERT);
updateBidi( e );
} finally {
writeUnlock();
}
}
|
public final synchronized void | readLock()Acquires a lock to begin reading some state from the
document. There can be multiple readers at the same time.
Writing blocks the readers until notification of the change
to the listeners has been completed. This method should
be used very carefully to avoid unintended compromise
of the document. It should always be balanced with a
readUnlock .
try {
while (currWriter != null) {
if (currWriter == Thread.currentThread()) {
// writer has full read access.... may try to acquire
// lock in notification
return;
}
wait();
}
numReaders += 1;
} catch (InterruptedException e) {
throw new Error("Interrupted attempt to aquire read lock");
}
|
private void | readObject(java.io.ObjectInputStream s)
s.defaultReadObject();
listenerList = new EventListenerList();
// Restore bidi structure
//REMIND(bcb) This creates an initial bidi element to account for
//the \n that exists by default in the content.
bidiRoot = new BidiRootElement();
try {
writeLock();
Element[] p = new Element[1];
p[0] = new BidiElement( bidiRoot, 0, 1, 0 );
bidiRoot.replace(0,0,p);
} finally {
writeUnlock();
}
// At this point bidi root is only partially correct. To fully
// restore it we need access to getDefaultRootElement. But, this
// is created by the subclass and at this point will be null. We
// thus use registerValidation.
s.registerValidation(new ObjectInputValidation() {
public void validateObject() {
try {
writeLock();
DefaultDocumentEvent e = new DefaultDocumentEvent
(0, getLength(),
DocumentEvent.EventType.INSERT);
updateBidi( e );
}
finally {
writeUnlock();
}
}
}, 0);
|
public final synchronized void | readUnlock()Does a read unlock. This signals that one
of the readers is done. If there are no more readers
then writing can begin again. This should be balanced
with a readLock, and should occur in a finally statement
so that the balance is guaranteed. The following is an
example.
readLock();
try {
// do something
} finally {
readUnlock();
}
if (currWriter == Thread.currentThread()) {
// writer has full read access.... may try to acquire
// lock in notification
return;
}
if (numReaders <= 0) {
throw new StateInvariantError(BAD_LOCK_STATE);
}
numReaders -= 1;
notify();
|
public void | remove(int offs, int len)Removes some content from the document.
Removing content causes a write lock to be held while the
actual changes are taking place. Observers are notified
of the change on the thread that called this method.
This method is thread safe, although most Swing methods
are not. Please see
How
to Use Threads for more information.
DocumentFilter filter = getDocumentFilter();
writeLock();
try {
if (filter != null) {
filter.remove(getFilterBypass(), offs, len);
}
else {
handleRemove(offs, len);
}
} finally {
writeUnlock();
}
|
public void | removeDocumentListener(javax.swing.event.DocumentListener listener)Removes a document listener.
listenerList.remove(DocumentListener.class, listener);
|
public void | removeUndoableEditListener(javax.swing.event.UndoableEditListener listener)Removes an undo listener.
listenerList.remove(UndoableEditListener.class, listener);
|
protected void | removeUpdate(javax.swing.text.AbstractDocument$DefaultDocumentEvent chng)Updates any document structure as a result of text removal. This
method is called before the text is actually removed from the Content.
This will happen within a write lock. If a subclass
of this class reimplements this method, it should delegate to the
superclass as well.
|
public void | render(java.lang.Runnable r)This allows the model to be safely rendered in the presence
of currency, if the model supports being updated asynchronously.
The given runnable will be executed in a way that allows it
to safely read the model with no changes while the runnable
is being executed. The runnable itself may not
make any mutations.
This is implemented to aquire a read lock for the duration
of the runnables execution. There may be multiple runnables
executing at the same time, and all writers will be blocked
while there are active rendering runnables. If the runnable
throws an exception, its lock will be safely released.
There is no protection against a runnable that never exits,
which will effectively leave the document locked for it's
lifetime.
If the given runnable attempts to make any mutations in
this implementation, a deadlock will occur. There is
no tracking of individual rendering threads to enable
detecting this situation, but a subclass could incur
the overhead of tracking them and throwing an error.
This method is thread safe, although most Swing methods
are not. Please see
How
to Use Threads for more information.
readLock();
try {
r.run();
} finally {
readUnlock();
}
|
public void | replace(int offset, int length, java.lang.String text, javax.swing.text.AttributeSet attrs)Deletes the region of text from offset to
offset + length , and replaces it with text .
It is up to the implementation as to how this is implemented, some
implementations may treat this as two distinct operations: a remove
followed by an insert, others may treat the replace as one atomic
operation.
if (length == 0 && (text == null || text.length() == 0)) {
return;
}
DocumentFilter filter = getDocumentFilter();
writeLock();
try {
if (filter != null) {
filter.replace(getFilterBypass(), offset, length, text,
attrs);
}
else {
if (length > 0) {
remove(offset, length);
}
if (text != null && text.length() > 0) {
insertString(offset, text, attrs);
}
}
} finally {
writeUnlock();
}
|
public void | setAsynchronousLoadPriority(int p)Sets the asynchronous loading priority.
Integer loadPriority = (p >= 0) ? new Integer(p) : null;
putProperty(AbstractDocument.AsyncLoadPriority, loadPriority);
|
public void | setDocumentFilter(javax.swing.text.DocumentFilter filter)Sets the DocumentFilter . The DocumentFilter
is passed insert and remove to conditionally
allow inserting/deleting of the text. A null value
indicates that no filtering will occur.
documentFilter = filter;
|
public void | setDocumentProperties(java.util.Dictionary x)Replaces the document properties dictionary for this document.
documentProperties = x;
|
void | updateBidi(javax.swing.text.AbstractDocument$DefaultDocumentEvent chng)Update the bidi element structure as a result of the given change
to the document. The given change will be updated to reflect the
changes made to the bidi structure.
This method assumes that every offset in the model is contained in
exactly one paragraph. This method also assumes that it is called
after the change is made to the default element structure.
// Calculate the range of paragraphs affected by the change.
int firstPStart;
int lastPEnd;
if( chng.type == DocumentEvent.EventType.INSERT
|| chng.type == DocumentEvent.EventType.CHANGE )
{
int chngStart = chng.getOffset();
int chngEnd = chngStart + chng.getLength();
firstPStart = getParagraphElement(chngStart).getStartOffset();
lastPEnd = getParagraphElement(chngEnd).getEndOffset();
} else if( chng.type == DocumentEvent.EventType.REMOVE ) {
Element paragraph = getParagraphElement( chng.getOffset() );
firstPStart = paragraph.getStartOffset();
lastPEnd = paragraph.getEndOffset();
} else {
throw new Error("Internal error: unknown event type.");
}
//System.out.println("updateBidi: firstPStart = " + firstPStart + " lastPEnd = " + lastPEnd );
// Calculate the bidi levels for the affected range of paragraphs. The
// levels array will contain a bidi level for each character in the
// affected text.
byte levels[] = calculateBidiLevels( firstPStart, lastPEnd );
Vector newElements = new Vector();
// Calculate the first span of characters in the affected range with
// the same bidi level. If this level is the same as the level of the
// previous bidi element (the existing bidi element containing
// firstPStart-1), then merge in the previous element. If not, but
// the previous element overlaps the affected range, truncate the
// previous element at firstPStart.
int firstSpanStart = firstPStart;
int removeFromIndex = 0;
if( firstSpanStart > 0 ) {
int prevElemIndex = bidiRoot.getElementIndex(firstPStart-1);
removeFromIndex = prevElemIndex;
Element prevElem = bidiRoot.getElement(prevElemIndex);
int prevLevel=StyleConstants.getBidiLevel(prevElem.getAttributes());
//System.out.println("createbidiElements: prevElem= " + prevElem + " prevLevel= " + prevLevel + "level[0] = " + levels[0]);
if( prevLevel==levels[0] ) {
firstSpanStart = prevElem.getStartOffset();
} else if( prevElem.getEndOffset() > firstPStart ) {
newElements.addElement(new BidiElement(bidiRoot,
prevElem.getStartOffset(),
firstPStart, prevLevel));
} else {
removeFromIndex++;
}
}
int firstSpanEnd = 0;
while((firstSpanEnd<levels.length) && (levels[firstSpanEnd]==levels[0]))
firstSpanEnd++;
// Calculate the last span of characters in the affected range with
// the same bidi level. If this level is the same as the level of the
// next bidi element (the existing bidi element containing lastPEnd),
// then merge in the next element. If not, but the next element
// overlaps the affected range, adjust the next element to start at
// lastPEnd.
int lastSpanEnd = lastPEnd;
Element newNextElem = null;
int removeToIndex = bidiRoot.getElementCount() - 1;
if( lastSpanEnd <= getLength() ) {
int nextElemIndex = bidiRoot.getElementIndex( lastPEnd );
removeToIndex = nextElemIndex;
Element nextElem = bidiRoot.getElement( nextElemIndex );
int nextLevel = StyleConstants.getBidiLevel(nextElem.getAttributes());
if( nextLevel == levels[levels.length-1] ) {
lastSpanEnd = nextElem.getEndOffset();
} else if( nextElem.getStartOffset() < lastPEnd ) {
newNextElem = new BidiElement(bidiRoot, lastPEnd,
nextElem.getEndOffset(),
nextLevel);
} else {
removeToIndex--;
}
}
int lastSpanStart = levels.length;
while( (lastSpanStart>firstSpanEnd)
&& (levels[lastSpanStart-1]==levels[levels.length-1]) )
lastSpanStart--;
// If the first and last spans are contiguous and have the same level,
// merge them and create a single new element for the entire span.
// Otherwise, create elements for the first and last spans as well as
// any spans in between.
if((firstSpanEnd==lastSpanStart)&&(levels[0]==levels[levels.length-1])){
newElements.addElement(new BidiElement(bidiRoot, firstSpanStart,
lastSpanEnd, levels[0]));
} else {
// Create an element for the first span.
newElements.addElement(new BidiElement(bidiRoot, firstSpanStart,
firstSpanEnd+firstPStart,
levels[0]));
// Create elements for the spans in between the first and last
for( int i=firstSpanEnd; i<lastSpanStart; ) {
//System.out.println("executed line 872");
int j;
for( j=i; (j<levels.length) && (levels[j] == levels[i]); j++ );
newElements.addElement(new BidiElement(bidiRoot, firstPStart+i,
firstPStart+j,
(int)levels[i]));
i=j;
}
// Create an element for the last span.
newElements.addElement(new BidiElement(bidiRoot,
lastSpanStart+firstPStart,
lastSpanEnd,
levels[levels.length-1]));
}
if( newNextElem != null )
newElements.addElement( newNextElem );
// Calculate the set of existing bidi elements which must be
// removed.
int removedElemCount = 0;
if( bidiRoot.getElementCount() > 0 ) {
removedElemCount = removeToIndex - removeFromIndex + 1;
}
Element[] removedElems = new Element[removedElemCount];
for( int i=0; i<removedElemCount; i++ ) {
removedElems[i] = bidiRoot.getElement(removeFromIndex+i);
}
Element[] addedElems = new Element[ newElements.size() ];
newElements.copyInto( addedElems );
// Update the change record.
ElementEdit ee = new ElementEdit( bidiRoot, removeFromIndex,
removedElems, addedElems );
chng.addEdit( ee );
// Update the bidi element structure.
bidiRoot.replace( removeFromIndex, removedElems.length, addedElems );
|
protected final synchronized void | writeLock()Acquires a lock to begin mutating the document this lock
protects. There can be no writing, notification of changes, or
reading going on in order to gain the lock. Additionally a thread is
allowed to gain more than one writeLock ,
as long as it doesn't attempt to gain additional writeLock s
from within document notification. Attempting to gain a
writeLock from within a DocumentListener notification will
result in an IllegalStateException . The ability
to obtain more than one writeLock per thread allows
subclasses to gain a writeLock, perform a number of operations, then
release the lock.
Calls to writeLock
must be balanced with calls to writeUnlock , else the
Document will be left in a locked state so that no
reading or writing can be done.
try {
while ((numReaders > 0) || (currWriter != null)) {
if (Thread.currentThread() == currWriter) {
if (notifyingListeners) {
// Assuming one doesn't do something wrong in a
// subclass this should only happen if a
// DocumentListener tries to mutate the document.
throw new IllegalStateException(
"Attempt to mutate in notification");
}
numWriters++;
return;
}
wait();
}
currWriter = Thread.currentThread();
numWriters = 1;
} catch (InterruptedException e) {
throw new Error("Interrupted attempt to aquire write lock");
}
|
protected final synchronized void | writeUnlock()Releases a write lock previously obtained via writeLock .
After decrementing the lock count if there are no oustanding locks
this will allow a new writer, or readers.
if (--numWriters <= 0) {
numWriters = 0;
currWriter = null;
notifyAll();
}
|