javax.swing.text
public class: PlainDocument [javadoc |
source]
java.lang.Object
javax.swing.text.AbstractDocument
javax.swing.text.PlainDocument
All Implemented Interfaces:
Document, Serializable
Direct Known Subclasses:
FloatNumberDocument, AutoCompleteDocument, BealeDocument, TextAreaDocument, DateDocument, CyrillicDocument, NumberDocument, UpperCaseDocument, NumericPlainDocument, NumberDocument, NumberDocument, JTextFieldValidation, FixedLengthDocument, CompilableStringDocument, NumberDocument
A plain document that maintains no character attributes. The
default element structure for this document is a map of the lines in
the text. The Element returned by getDefaultRootElement is
a map of the lines, and each child element represents a line.
This model does not maintain any character level attributes,
but each line can be tagged with an arbitrary set of attributes.
Line to offset, and offset to line translations can be quickly
performed using the default root element. The structure information
of the DocumentEvent's fired by edits will indicate the line
structure changes.
The default content storage management is performed by a
gapped buffer implementation (GapContent). It supports
editing reasonably large documents with good efficiency when
the edits are contiguous or clustered, as is typical.
Warning:
Serialized objects of this class will not be compatible with
future Swing releases. The current serialization support is
appropriate for short term storage or RMI between applications running
the same version of Swing. As of 1.4, support for long term storage
of all JavaBeansTM
has been added to the java.beans
package.
Please see java.beans.XMLEncoder .
Field Summary |
---|
public static final String | tabSizeAttribute | Name of the attribute that specifies the tab
size for tabs contained in the content. The
type for the value is Integer. |
public static final String | lineLimitAttribute | Name of the attribute that specifies the maximum
length of a line, if there is a maximum length.
The type for the value is Integer. |
Methods from javax.swing.text.AbstractDocument: |
---|
addDocumentListener, addUndoableEditListener, createBranchElement, createLeafElement, createPosition, dump, fireChangedUpdate, fireInsertUpdate, fireRemoveUpdate, fireUndoableEditUpdate, getAsynchronousLoadPriority, getAttributeContext, getBidiRootElement, getContent, getCurrentWriter, getDefaultRootElement, getDocumentFilter, getDocumentListeners, getDocumentProperties, getEndPosition, getLength, getListeners, getParagraphElement, getProperty, getRootElements, getStartPosition, getText, getText, getUndoableEditListeners, handleInsertString, handleRemove, insertString, insertUpdate, isLeftToRight, postRemoveUpdate, putProperty, readLock, readUnlock, remove, removeDocumentListener, removeUndoableEditListener, removeUpdate, render, replace, setAsynchronousLoadPriority, setDocumentFilter, setDocumentProperties, updateBidi, writeLock, writeUnlock |
Methods from java.lang.Object: |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Method from javax.swing.text.PlainDocument Detail: |
protected AbstractElement createDefaultRoot() {
BranchElement map = (BranchElement) createBranchElement(null, null);
Element line = createLeafElement(map, null, 0, 1);
Element[] lines = new Element[1];
lines[0] = line;
map.replace(0, 0, lines);
return map;
}
Creates the root element to be used to represent the
default document structure. |
public Element getDefaultRootElement() {
return defaultRoot;
}
Gets the default root element for the document model. |
public Element getParagraphElement(int pos) {
Element lineMap = getDefaultRootElement();
return lineMap.getElement( lineMap.getElementIndex( pos ) );
}
Get the paragraph element containing the given position. Since this
document only models lines, it returns the line instead. |
public void insertString(int offs,
String str,
AttributeSet a) throws BadLocationException {
// fields don't want to have multiple lines. We may provide a field-specific
// model in the future in which case the filtering logic here will no longer
// be needed.
Object filterNewlines = getProperty("filterNewlines");
if ((filterNewlines instanceof Boolean) && filterNewlines.equals(Boolean.TRUE)) {
if ((str != null) && (str.indexOf('\n') >= 0)) {
StringBuilder filtered = new StringBuilder(str);
int n = filtered.length();
for (int i = 0; i < n; i++) {
if (filtered.charAt(i) == '\n') {
filtered.setCharAt(i, ' ');
}
}
str = filtered.toString();
}
}
super.insertString(offs, str, 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. |
protected void insertUpdate(DefaultDocumentEvent chng,
AttributeSet attr) {
removed.removeAllElements();
added.removeAllElements();
BranchElement lineMap = (BranchElement) getDefaultRootElement();
int offset = chng.getOffset();
int length = chng.getLength();
if (offset > 0) {
offset -= 1;
length += 1;
}
int index = lineMap.getElementIndex(offset);
Element rmCandidate = lineMap.getElement(index);
int rmOffs0 = rmCandidate.getStartOffset();
int rmOffs1 = rmCandidate.getEndOffset();
int lastOffset = rmOffs0;
try {
if (s == null) {
s = new Segment();
}
getContent().getChars(offset, length, s);
boolean hasBreaks = false;
for (int i = 0; i < length; i++) {
char c = s.array[s.offset + i];
if (c == '\n') {
int breakOffset = offset + i + 1;
added.addElement(createLeafElement(lineMap, null, lastOffset, breakOffset));
lastOffset = breakOffset;
hasBreaks = true;
}
}
if (hasBreaks) {
removed.addElement(rmCandidate);
if ((offset + length == rmOffs1) && (lastOffset != rmOffs1) &&
((index+1) < lineMap.getElementCount())) {
Element e = lineMap.getElement(index+1);
removed.addElement(e);
rmOffs1 = e.getEndOffset();
}
if (lastOffset < rmOffs1) {
added.addElement(createLeafElement(lineMap, null, lastOffset, rmOffs1));
}
Element[] aelems = new Element[added.size()];
added.copyInto(aelems);
Element[] relems = new Element[removed.size()];
removed.copyInto(relems);
ElementEdit ee = new ElementEdit(lineMap, index, relems, aelems);
chng.addEdit(ee);
lineMap.replace(index, relems.length, aelems);
}
if (Utilities.isComposedTextAttributeDefined(attr)) {
insertComposedTextUpdate(chng, attr);
}
} catch (BadLocationException e) {
throw new Error("Internal error: " + e.toString());
}
super.insertUpdate(chng, attr);
}
Updates document structure as a result of text insertion. This
will happen within a write lock. Since this document simply
maps out lines, we refresh the line map. |
protected void removeUpdate(DefaultDocumentEvent chng) {
removed.removeAllElements();
BranchElement map = (BranchElement) getDefaultRootElement();
int offset = chng.getOffset();
int length = chng.getLength();
int line0 = map.getElementIndex(offset);
int line1 = map.getElementIndex(offset + length);
if (line0 != line1) {
// a line was removed
for (int i = line0; i < = line1; i++) {
removed.addElement(map.getElement(i));
}
int p0 = map.getElement(line0).getStartOffset();
int p1 = map.getElement(line1).getEndOffset();
Element[] aelems = new Element[1];
aelems[0] = createLeafElement(map, null, p0, p1);
Element[] relems = new Element[removed.size()];
removed.copyInto(relems);
ElementEdit ee = new ElementEdit(map, line0, relems, aelems);
chng.addEdit(ee);
map.replace(line0, relems.length, aelems);
} else {
//Check for the composed text element
Element line = map.getElement(line0);
if (!line.isLeaf()) {
Element leaf = line.getElement(line.getElementIndex(offset));
if (Utilities.isComposedTextElement(leaf)) {
Element[] aelem = new Element[1];
aelem[0] = createLeafElement(map, null,
line.getStartOffset(), line.getEndOffset());
Element[] relem = new Element[1];
relem[0] = line;
ElementEdit ee = new ElementEdit(map, line0, relem, aelem);
chng.addEdit(ee);
map.replace(line0, 1, aelem);
}
}
}
super.removeUpdate(chng);
}
Updates any document structure as a result of text removal.
This will happen within a write lock. Since the structure
represents a line map, this just checks to see if the
removal spans lines. If it does, the two lines outside
of the removal area are joined together. |