paintLayeredHighlight
which
* will result in a rectangle being drawn before the text is drawn
* (if the offsets are in a highlighted region that is). For this to
* work the painter supplied must be an instance of
* LayeredHighlightPainter.
*/
public void setDrawsLayeredHighlights(boolean newValue) {
drawsLayeredHighlights = newValue;
}
public boolean getDrawsLayeredHighlights() {
return drawsLayeredHighlights;
}
// ---- member variables --------------------------------------------
private final static Highlighter.Highlight[] noHighlights =
new Highlighter.Highlight[0];
private Vector
* As of 1.4 this field is final.
*/
public static final LayeredHighlighter.LayerPainter DefaultPainter = new DefaultHighlightPainter(null);
/**
* Simple highlight painter that fills a highlighted area with
* a solid color.
*/
public static class DefaultHighlightPainter extends LayeredHighlighter.LayerPainter {
/**
* Constructs a new highlight painter. If c
is null,
* the JTextComponent will be queried for its selection color.
*
* @param c the color for the highlight
*/
public DefaultHighlightPainter(Color c) {
color = c;
}
/**
* Returns the color of the highlight.
*
* @return the color
*/
public Color getColor() {
return color;
}
// --- HighlightPainter methods ---------------------------------------
/**
* Paints a highlight.
*
* @param g the graphics context
* @param offs0 the starting model offset >= 0
* @param offs1 the ending model offset >= offs1
* @param bounds the bounding box for the highlight
* @param c the editor
*/
public void paint(Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c) {
Rectangle alloc = bounds.getBounds();
try {
// --- determine locations ---
TextUI mapper = c.getUI();
Rectangle p0 = mapper.modelToView(c, offs0);
Rectangle p1 = mapper.modelToView(c, offs1);
// --- render ---
Color color = getColor();
if (color == null) {
g.setColor(c.getSelectionColor());
}
else {
g.setColor(color);
}
if (p0.y == p1.y) {
// same line, render a rectangle
Rectangle r = p0.union(p1);
g.fillRect(r.x, r.y, r.width, r.height);
} else {
// different lines
int p0ToMarginWidth = alloc.x + alloc.width - p0.x;
g.fillRect(p0.x, p0.y, p0ToMarginWidth, p0.height);
if ((p0.y + p0.height) != p1.y) {
g.fillRect(alloc.x, p0.y + p0.height, alloc.width,
p1.y - (p0.y + p0.height));
}
g.fillRect(alloc.x, p1.y, (p1.x - alloc.x), p1.height);
}
} catch (BadLocationException e) {
// can't render
}
}
// --- LayerPainter methods ----------------------------
/**
* Paints a portion of a highlight.
*
* @param g the graphics context
* @param offs0 the starting model offset >= 0
* @param offs1 the ending model offset >= offs1
* @param bounds the bounding box of the view, which is not
* necessarily the region to paint.
* @param c the editor
* @param view View painting for
* @return region drawing occured in
*/
public Shape paintLayer(Graphics g, int offs0, int offs1,
Shape bounds, JTextComponent c, View view) {
Color color = getColor();
if (color == null) {
g.setColor(c.getSelectionColor());
}
else {
g.setColor(color);
}
Rectangle r;
if (offs0 == view.getStartOffset() &&
offs1 == view.getEndOffset()) {
// Contained in view, can just use bounds.
if (bounds instanceof Rectangle) {
r = (Rectangle) bounds;
}
else {
r = bounds.getBounds();
}
}
else {
// Should only render part of View.
try {
// --- determine locations ---
Shape shape = view.modelToView(offs0, Position.Bias.Forward,
offs1,Position.Bias.Backward,
bounds);
r = (shape instanceof Rectangle) ?
(Rectangle)shape : shape.getBounds();
} catch (BadLocationException e) {
// can't render
r = null;
}
}
if (r != null) {
// If we are asked to highlight, we should draw something even
// if the model-to-view projection is of zero width (6340106).
r.width = Math.max(r.width, 1);
g.fillRect(r.x, r.y, r.width, r.height);
}
return r;
}
private Color color;
}
class HighlightInfo implements Highlighter.Highlight {
public int getStartOffset() {
return p0.getOffset();
}
public int getEndOffset() {
return p1.getOffset();
}
public Highlighter.HighlightPainter getPainter() {
return painter;
}
Position p0;
Position p1;
Highlighter.HighlightPainter painter;
}
/**
* LayeredHighlightPainter is used when a drawsLayeredHighlights is
* true. It maintains a rectangle of the region to paint.
*/
class LayeredHighlightInfo extends HighlightInfo {
void union(Shape bounds) {
if (bounds == null)
return;
Rectangle alloc;
if (bounds instanceof Rectangle) {
alloc = (Rectangle)bounds;
}
else {
alloc = bounds.getBounds();
}
if (width == 0 || height == 0) {
x = alloc.x;
y = alloc.y;
width = alloc.width;
height = alloc.height;
}
else {
width = Math.max(x + width, alloc.x + alloc.width);
height = Math.max(y + height, alloc.y + alloc.height);
x = Math.min(x, alloc.x);
width -= x;
y = Math.min(y, alloc.y);
height -= y;
}
}
/**
* Restricts the region based on the receivers offsets and messages
* the painter to paint the region.
*/
void paintLayeredHighlights(Graphics g, int p0, int p1,
Shape viewBounds, JTextComponent editor,
View view) {
int start = getStartOffset();
int end = getEndOffset();
// Restrict the region to what we represent
p0 = Math.max(start, p0);
p1 = Math.min(end, p1);
// Paint the appropriate region using the painter and union
// the effected region with our bounds.
union(((LayeredHighlighter.LayerPainter)painter).paintLayer
(g, p0, p1, viewBounds, editor, view));
}
int x;
int y;
int width;
int height;
}
/**
* This class invokes mapper.damageRange
in
* EventDispatchThread. The only one instance per Highlighter
* is cretaed. When a number of ranges should be damaged
* it collects them into queue and damages
* them in consecutive order in run
* call.
*/
class SafeDamager implements Runnable {
private Vector