📄 wrappedsyntaxview_test.java
字号:
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); // Metrics for the default font.
tabSize = getTabSize() * metrics.charWidth('m');
}
/*****************************************************************************/
/******************* PRIVATE INNER CLASSES ***********************************/
/*****************************************************************************/
/**
* Simple view of a line that wraps if it doesn't
* fit withing the horizontal space allocated.
* This class tries to be lightweight by carrying little
* state of it's own and sharing the state of the outer class
* with it's siblings.
*/
class WrappedLine extends View {
int nlines;
WrappedLine(Element elem) {
super(elem);
}
/**
* Calculate the number of lines that will be rendered
* by logical line when it is wrapped.
*/
final int calculateLineCount() {
int nlines = 0;
int startOffset = getStartOffset();
int p1 = getEndOffset();
// Get the token list for this line so we don't have to keep
// recomputing it if this logical line spans multiple physical
// lines.
RSyntaxTextArea textArea = (RSyntaxTextArea)getContainer();
RSyntaxDocument doc = (RSyntaxDocument)getDocument();
Element map = doc.getDefaultRootElement();
int line = map.getElementIndex(startOffset);
Token tokenList = doc.getTokenListForLine(line);
float x0 = 0;// FIXME: should be alloc.x!! alloc.x;//0;
//System.err.println(">>> calculateLineCount: " + startOffset + "-" + p1);
for (int p0=startOffset; p0<p1; ) {
//System.err.println("... ... " + p0 + ", " + p1);
nlines += 1;
x0 = RSyntaxUtilities.makeTokenListStartAt(tokenList, p0,
WrappedSyntaxView_TEST.this, textArea, x0);
int p = calculateBreakPosition(p0, tokenList, x0);
//System.err.println("... ... ... break position p==" + p);
p0 = (p == p0) ? ++p : p; // this is the fix of #4410243
// we check on situation when
// width is too small and
// break position is calculated
// incorrectly.
//System.err.println("... ... ... new p0==" + p0);
}
/*
int numLines = 0;
try {
numLines = textArea.getLineCount();
} catch (BadLocationException ble) {
ble.printStackTrace();
System.exit(0);
}
System.err.println(">>> >>> calculated number of lines for this view (line " + line + "/" + numLines + ": " + nlines);
*/
return nlines;
}
/**
* Determines the preferred span for this view along an
* axis.
*
* @param axis may be either X_AXIS or Y_AXIS
* @return the span the view would like to be rendered into.
* Typically the view is told to render into the span
* that is returned, although there is no guarantee.
* The parent may choose to resize or break the view.
* @see View#getPreferredSpan
*/
public float getPreferredSpan(int axis) {
switch (axis) {
case View.X_AXIS:
float width = getWidth();
if (width == Integer.MAX_VALUE) {
// We have been initially set to MAX_VALUE, but we don't
// want this as our preferred.
return 100f;
}
return width;
case View.Y_AXIS:
if (nlines == 0 || widthChanging)
nlines = calculateLineCount();
int h = nlines * ((RSyntaxTextArea)getContainer()).getLineHeight();
return h;
default:
throw new IllegalArgumentException("Invalid axis: " + axis);
}
}
/**
* Renders using the given rendering surface and area on that
* surface. The view may need to do layout and create child
* views to enable itself to render into the given allocation.
*
* @param g the rendering surface to use
* @param a the allocated region to render into
* @see View#paint
*/
public void paint(Graphics g, Shape a) {
// This is done by drawView() above.
}
/**
* Provides a mapping from the document model coordinate space
* to the coordinate space of the view mapped to it.
*
* @param pos the position to convert
* @param a the allocated region to render into
* @return the bounding box of the given position is returned
* @exception BadLocationException if the given position does not
* represent a valid location in the associated document.
*/
public Shape modelToView(int pos, Shape a, Position.Bias b)
throws BadLocationException {
//System.err.println("--- begin modelToView ---");
Rectangle alloc = a.getBounds();
RSyntaxTextArea textArea = (RSyntaxTextArea)getContainer();
alloc.height = textArea.getLineHeight();//metrics.getHeight();
alloc.width = 1;
int p0 = getStartOffset();
int p1 = getEndOffset();
int testP = (b == Position.Bias.Forward) ? pos :
Math.max(p0, pos - 1);
// Get the token list for this line so we don't have to keep
// recomputing it if this logical line spans multiple physical
// lines.
RSyntaxDocument doc = (RSyntaxDocument)getDocument();
Element map = doc.getDefaultRootElement();
int line = map.getElementIndex(p0);
Token tokenList = doc.getTokenListForLine(line);
float x0 = alloc.x;//0;
while (p0 < p1) {
x0 = RSyntaxUtilities.makeTokenListStartAt(tokenList, p0,
WrappedSyntaxView_TEST.this, textArea, x0);
int p = calculateBreakPosition(p0, tokenList, x0);
if ((pos >= p0) && (testP<p)) {//pos < p)) {
// it's in this line
alloc = RSyntaxUtilities.getLineWidthUpTo(
textArea, s, p0, pos,
WrappedSyntaxView_TEST.this,
alloc, alloc.x);
//System.err.println("--- end modelToView ---");
return alloc;
}
//if (p == p1 && pos == p1) {
if (p==p1-1 && pos==p1-1) {
// Wants end.
if (pos > p0) {
alloc = RSyntaxUtilities.getLineWidthUpTo(
textArea, s, p0, pos,
WrappedSyntaxView_TEST.this,
alloc, alloc.x);
}
//System.err.println("--- end modelToView ---");
return alloc;
}
p0 = (p == p0) ? p1 : p;
//System.err.println("... ... Incrementing y");
alloc.y += alloc.height;
}
throw new BadLocationException(null, pos);
}
/**
* Provides a mapping from the view coordinate space to the logical
* coordinate space of the model.
*
* @param x the X coordinate
* @param y the Y coordinate
* @param a the allocated region to render into
* @return the location within the model that best represents the
* given point in the view
* @see View#viewToModel
*/
public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) {
// PENDING(prinz) implement bias properly
bias[0] = Position.Bias.Forward;
Rectangle alloc = (Rectangle) a;
RSyntaxDocument doc = (RSyntaxDocument)getDocument();
int x = (int) fx;
int y = (int) fy;
if (y < alloc.y) {
// above the area covered by this icon, so the the position
// is assumed to be the start of the coverage for this view.
return getStartOffset();
}
else if (y > alloc.y + alloc.height) {
// below the area covered by this icon, so the the position
// is assumed to be the end of the coverage for this view.
return getEndOffset() - 1;
}
else {
// positioned within the coverage of this view vertically,
// so we figure out which line the point corresponds to.
// if the line is greater than the number of lines
// contained, then simply use the last line as it represents
// the last possible place we can position to.
RSyntaxTextArea textArea = (RSyntaxTextArea)getContainer();
alloc.height = textArea.getLineHeight();
int p1 = getEndOffset();
// Get the token list for this line so we don't have to keep
// recomputing it if this logical line spans multiple
// physical lines.
Element map = doc.getDefaultRootElement();
int p0 = getStartOffset();
int line = map.getElementIndex(p0);
Token tlist = doc.getTokenListForLine(line);
// Look at each physical line-chunk of this logical line.
while (p0<p1) {
// We can always use alloc.x since we always break
// lines so they start at the beginning of a physical
// line.
RSyntaxUtilities.makeTokenListStartAt(tlist, p0,
WrappedSyntaxView_TEST.this, textArea, alloc.x);
int p = calculateBreakPosition(p0, tlist, alloc.x);
// If desired view position is in this physical chunk.
if ((y>=alloc.y) && (y<(alloc.y+alloc.height))) {
// Point is to the left of the line
if (x < alloc.x) {
return p0;
}
// Point is to the right of the line
else if (x > alloc.x + alloc.width) {
return p - 1;
}
// Point is in this physical line!
else {
// Start at alloc.x since this chunk starts
// at the beginning of a physical line.
int n = tlist.getListOffset(textArea,
WrappedSyntaxView_TEST.this,
alloc.x, x);
// NOTE: We needed to add the max() with
// p0 as getTokenListForLine returns -1
// for empty lines (just a null token).
// How did this work before?
// FIXME: Have null tokens have their
// offset but a -1 length.
return Math.max(Math.min(n, p1-1), p0);
} // End of else.
} // End of if ((y>=alloc.y) && ...
p0 = (p == p0) ? p1 : p;
alloc.y += alloc.height;
} // End of while (p0<p1).
return getEndOffset() - 1;
} // End of else.
}
public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
int n = calculateLineCount();
if (this.nlines != n) {
this.nlines = n;
WrappedSyntaxView_TEST.this.preferenceChanged(this, false, true);
// have to repaint any views after the receiver.
getContainer().repaint();
}
else if (a != null) {
Component c = getContainer();
Rectangle alloc = (Rectangle) a;
c.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
}
}
public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
int n = calculateLineCount();
if (this.nlines != n) {
// have to repaint any views after the receiver.
this.nlines = n;
WrappedSyntaxView_TEST.this.preferenceChanged(this, false, true);
getContainer().repaint();
}
else if (a != null) {
Component c = getContainer();
Rectangle alloc = (Rectangle) a;
c.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
}
}
}
/*****************************************************************************/
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -