WrappedPlainViewpublic class WrappedPlainView extends BoxView implements TabExpanderView of plain text (text with only one font and color)
that does line-wrapping. This view expects that its
associated element has child elements that represent
the lines it should be wrapping. It is implemented
as a vertical box that contains logical line views.
The logical line views are nested classes that render
the logical line as multiple physical line if the logical
line is too wide to fit within the allocation. The
line views draw upon the outer class for its state
to reduce their memory requirements.
The line views do all of their rendering through the
drawLine method which in turn does all of
its rendering through the drawSelectedText
and drawUnselectedText methods. This
enables subclasses to easily specialize the rendering
without concern for the layout aspects. |
Fields Summary |
---|
FontMetrics | metrics | Segment | lineBuffer | boolean | widthChanging | int | tabBase | int | tabSize | boolean | wordWrap | int | sel0 | int | sel1 | Color | unselected | Color | selected |
Constructors Summary |
---|
public WrappedPlainView(Element elem)Creates a new WrappedPlainView. Lines will be wrapped
on character boundaries.
this(elem, false);
| public WrappedPlainView(Element elem, boolean wordWrap)Creates a new WrappedPlainView. Lines can be wrapped on
either character or word boundaries depending upon the
setting of the wordWrap parameter.
super(elem, Y_AXIS);
this.wordWrap = wordWrap;
|
Methods Summary |
---|
protected int | calculateBreakPosition(int p0, int p1)This is called by the nested wrapped line
views to determine the break location. This can
be reimplemented to alter the breaking behavior.
It will either break at word or character boundaries
depending upon the break argument given at
construction.
int p;
Segment segment = SegmentCache.getSharedSegment();
loadText(segment, p0, p1);
int currentWidth = getWidth();
if (wordWrap) {
p = p0 + Utilities.getBreakLocation(segment, metrics,
tabBase, tabBase + currentWidth,
this, p0);
} else {
p = p0 + Utilities.getTabbedTextOffset(segment, metrics,
tabBase, tabBase + currentWidth,
this, p0, false);
}
SegmentCache.releaseSharedSegment(segment);
return p;
| public void | changedUpdate(javax.swing.event.DocumentEvent e, java.awt.Shape a, javax.swing.text.ViewFactory f)Gives notification from the document that attributes were changed
in a location that this view is responsible for.
updateChildren(e, a);
| protected void | drawLine(int p0, int p1, java.awt.Graphics g, int x, int y)Renders a line of text, suppressing whitespace at the end
and expanding any tabs. This is implemented to make calls
to the methods drawUnselectedText and
drawSelectedText so that the way selected and
unselected text are rendered can be customized.
Element lineMap = getElement();
Element line = lineMap.getElement(lineMap.getElementIndex(p0));
Element elem;
try {
if (line.isLeaf()) {
drawText(line, p0, p1, g, x, y);
} else {
// this line contains the composed text.
int idx = line.getElementIndex(p0);
int lastIdx = line.getElementIndex(p1);
for(; idx <= lastIdx; idx++) {
elem = line.getElement(idx);
int start = Math.max(elem.getStartOffset(), p0);
int end = Math.min(elem.getEndOffset(), p1);
x = drawText(elem, start, end, g, x, y);
}
}
} catch (BadLocationException e) {
throw new StateInvariantError("Can't render: " + p0 + "," + p1);
}
| protected int | drawSelectedText(java.awt.Graphics g, int x, int y, int p0, int p1)Renders the given range in the model as selected text. This
is implemented to render the text in the color specified in
the hosting component. It assumes the highlighter will render
the selected background.
g.setColor(selected);
Document doc = getDocument();
Segment segment = SegmentCache.getSharedSegment();
doc.getText(p0, p1 - p0, segment);
int ret = Utilities.drawTabbedText(this, segment, x, y, g, this, p0);
SegmentCache.releaseSharedSegment(segment);
return ret;
| private int | drawText(javax.swing.text.Element elem, int p0, int p1, java.awt.Graphics g, int x, int y)
p1 = Math.min(getDocument().getLength(), p1);
AttributeSet attr = elem.getAttributes();
if (Utilities.isComposedTextAttributeDefined(attr)) {
g.setColor(unselected);
x = Utilities.drawComposedText(this, attr, g, x, y,
p0-elem.getStartOffset(),
p1-elem.getStartOffset());
} else {
if (sel0 == sel1 || selected == unselected) {
// no selection, or it is invisible
x = drawUnselectedText(g, x, y, p0, p1);
} else if ((p0 >= sel0 && p0 <= sel1) && (p1 >= sel0 && p1 <= sel1)) {
x = drawSelectedText(g, x, y, p0, p1);
} else if (sel0 >= p0 && sel0 <= p1) {
if (sel1 >= p0 && sel1 <= p1) {
x = drawUnselectedText(g, x, y, p0, sel0);
x = drawSelectedText(g, x, y, sel0, sel1);
x = drawUnselectedText(g, x, y, sel1, p1);
} else {
x = drawUnselectedText(g, x, y, p0, sel0);
x = drawSelectedText(g, x, y, sel0, p1);
}
} else if (sel1 >= p0 && sel1 <= p1) {
x = drawSelectedText(g, x, y, p0, sel1);
x = drawUnselectedText(g, x, y, sel1, p1);
} else {
x = drawUnselectedText(g, x, y, p0, p1);
}
}
return x;
| protected int | drawUnselectedText(java.awt.Graphics g, int x, int y, int p0, int p1)Renders the given range in the model as normal unselected
text.
g.setColor(unselected);
Document doc = getDocument();
Segment segment = SegmentCache.getSharedSegment();
doc.getText(p0, p1 - p0, segment);
int ret = Utilities.drawTabbedText(this, segment, x, y, g, this, p0);
SegmentCache.releaseSharedSegment(segment);
return ret;
| protected final javax.swing.text.Segment | getLineBuffer()Gives access to a buffer that can be used to fetch
text from the associated document.
if (lineBuffer == null) {
lineBuffer = new Segment();
}
return lineBuffer;
| public float | getMaximumSpan(int axis)Determines the maximum span for this view along an
axis. This is implemented to provide the superclass
behavior after first making sure that the current font
metrics are cached (for the nested lines which use
the metrics to determine the height of the potentially
wrapped lines).
updateMetrics();
return super.getMaximumSpan(axis);
| public float | getMinimumSpan(int axis)Determines the minimum span for this view along an
axis. This is implemented to provide the superclass
behavior after first making sure that the current font
metrics are cached (for the nested lines which use
the metrics to determine the height of the potentially
wrapped lines).
updateMetrics();
return super.getMinimumSpan(axis);
| public float | getPreferredSpan(int axis)Determines the preferred span for this view along an
axis. This is implemented to provide the superclass
behavior after first making sure that the current font
metrics are cached (for the nested lines which use
the metrics to determine the height of the potentially
wrapped lines).
updateMetrics();
return super.getPreferredSpan(axis);
| protected int | getTabSize()Returns the tab size set for the document, defaulting to 8.
Integer i = (Integer) getDocument().getProperty(PlainDocument.tabSizeAttribute);
int size = (i != null) ? i.intValue() : 8;
return size;
| public void | insertUpdate(javax.swing.event.DocumentEvent e, java.awt.Shape a, javax.swing.text.ViewFactory f)Gives notification that something was inserted into the
document in a location that this view is responsible for.
This is implemented to simply update the children.
updateChildren(e, a);
Rectangle alloc = ((a != null) && isAllocationValid()) ?
getInsideAllocation(a) : null;
int pos = e.getOffset();
View v = getViewAtPosition(pos, alloc);
if (v != null) {
v.insertUpdate(e, alloc, f);
}
| protected void | loadChildren(javax.swing.text.ViewFactory f)Loads all of the children to initialize the view.
This is called by the setParent method.
Subclasses can reimplement this to initialize their
child views in a different manner. The default
implementation creates a child view for each
child element.
Element e = getElement();
int n = e.getElementCount();
if (n > 0) {
View[] added = new View[n];
for (int i = 0; i < n; i++) {
added[i] = new WrappedLine(e.getElement(i));
}
replace(0, 0, added);
}
| final void | loadText(javax.swing.text.Segment segment, int p0, int p1)Load the text buffer with the given range
of text. This is used by the fragments
broken off of this view as well as this
view itself.
try {
Document doc = getDocument();
doc.getText(p0, p1 - p0, segment);
} catch (BadLocationException bl) {
throw new StateInvariantError("Can't get line text");
}
| public float | nextTabStop(float x, int tabOffset)Returns the next tab stop position after a given reference position.
This implementation does not support things like centering so it
ignores the tabOffset argument.
if (tabSize == 0)
return x;
int ntabs = ((int) x - tabBase) / tabSize;
return tabBase + ((ntabs + 1) * tabSize);
| public void | paint(java.awt.Graphics g, java.awt.Shape a)Renders using the given rendering surface and area
on that surface. This is implemented to stash the
selection positions, selection colors, and font
metrics for the nested lines to use.
Rectangle alloc = (Rectangle) a;
tabBase = alloc.x;
JTextComponent host = (JTextComponent) getContainer();
sel0 = host.getSelectionStart();
sel1 = host.getSelectionEnd();
unselected = (host.isEnabled()) ?
host.getForeground() : host.getDisabledTextColor();
Caret c = host.getCaret();
selected = c.isSelectionVisible() && host.getHighlighter() != null ?
host.getSelectedTextColor() : unselected;
g.setFont(host.getFont());
// superclass paints the children
super.paint(g, a);
| public void | removeUpdate(javax.swing.event.DocumentEvent e, java.awt.Shape a, javax.swing.text.ViewFactory f)Gives notification that something was removed from the
document in a location that this view is responsible for.
This is implemented to simply update the children.
updateChildren(e, a);
Rectangle alloc = ((a != null) && isAllocationValid()) ?
getInsideAllocation(a) : null;
int pos = e.getOffset();
View v = getViewAtPosition(pos, alloc);
if (v != null) {
v.removeUpdate(e, alloc, f);
}
| public void | setSize(float width, float height)Sets the size of the view. This should cause
layout of the view along the given axis, if it
has any layout duties.
updateMetrics();
if ((int) width != getWidth()) {
// invalidate the view itself since the childrens
// desired widths will be based upon this views width.
preferenceChanged(null, true, true);
widthChanging = true;
}
super.setSize(width, height);
widthChanging = false;
| void | updateChildren(javax.swing.event.DocumentEvent e, java.awt.Shape a)Update the child views in response to a
document event.
Element elem = getElement();
DocumentEvent.ElementChange ec = e.getChange(elem);
if (ec != null) {
// the structure of this element changed.
Element[] removedElems = ec.getChildrenRemoved();
Element[] addedElems = ec.getChildrenAdded();
View[] added = new View[addedElems.length];
for (int i = 0; i < addedElems.length; i++) {
added[i] = new WrappedLine(addedElems[i]);
}
replace(ec.getIndex(), removedElems.length, added);
// should damge a little more intelligently.
if (a != null) {
preferenceChanged(null, true, true);
getContainer().repaint();
}
}
// update font metrics which may be used by the child views
updateMetrics();
| final void | updateMetrics()
Component host = getContainer();
Font f = host.getFont();
metrics = host.getFontMetrics(f);
tabSize = getTabSize() * metrics.charWidth('m");
|
|