Browse Source

Merge pull request #1063 in DESIGN/design from ~BRUCE.DENG/design:feature/10.0 to feature/10.0

* commit '8877c174a2c75fb64d421db4ac3705aa240893e9':
  REPORT-20318 sonar问题修复-zack
research/11.0
Bruce.Deng 5 years ago
parent
commit
5108f6b353
  1. 457
      designer-base/src/main/java/com/fr/design/gui/syntax/ui/rsyntaxtextarea/SyntaxView.java
  2. 145
      designer-base/src/main/java/com/fr/design/gui/syntax/ui/rsyntaxtextarea/WrappedSyntaxView.java

457
designer-base/src/main/java/com/fr/design/gui/syntax/ui/rsyntaxtextarea/SyntaxView.java

@ -3,30 +3,43 @@
* *
* SyntaxView.java - The View object used by RSyntaxTextArea when word wrap is * SyntaxView.java - The View object used by RSyntaxTextArea when word wrap is
* disabled. * disabled.
* *
* This library is distributed under a modified BSD license. See the included * This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details. * RSyntaxTextArea.License.txt file for details.
*/ */
package com.fr.design.gui.syntax.ui.rsyntaxtextarea; package com.fr.design.gui.syntax.ui.rsyntaxtextarea;
import java.awt.*;
import javax.swing.event.*;
import javax.swing.text.*;
import com.fr.design.gui.syntax.ui.rsyntaxtextarea.folding.Fold; import com.fr.design.gui.syntax.ui.rsyntaxtextarea.folding.Fold;
import com.fr.design.gui.syntax.ui.rsyntaxtextarea.folding.FoldManager; import com.fr.design.gui.syntax.ui.rsyntaxtextarea.folding.FoldManager;
import javax.swing.event.DocumentEvent;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.PlainDocument;
import javax.swing.text.Position;
import javax.swing.text.TabExpander;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
/** /**
* The <code>javax.swing.text.View</code> object used by {@link RSyntaxTextArea} * The <code>javax.swing.text.View</code> object used by {@link RSyntaxTextArea}
* when word wrap is disabled. It implements syntax highlighting for * when word wrap is disabled. It implements syntax highlighting for
* programming languages using the colors and font styles specified by the * programming languages using the colors and font styles specified by the
* <code>RSyntaxTextArea</code>.<p> * <code>RSyntaxTextArea</code>.<p>
* * <p>
* You don't really have to do anything to use this class, as * You don't really have to do anything to use this class, as
* {@link RSyntaxTextAreaUI} automatically sets the text area's view to be * {@link RSyntaxTextAreaUI} automatically sets the text area's view to be
* an instance of this class if word wrap is disabled.<p> * an instance of this class if word wrap is disabled.<p>
* * <p>
* The tokens that specify how to paint the syntax-highlighted text are gleaned * The tokens that specify how to paint the syntax-highlighted text are gleaned
* from the text area's {@link RSyntaxDocument}. * from the text area's {@link RSyntaxDocument}.
* *
@ -34,7 +47,7 @@ import com.fr.design.gui.syntax.ui.rsyntaxtextarea.folding.FoldManager;
* @version 0.3 * @version 0.3
*/ */
public class SyntaxView extends View implements TabExpander, public class SyntaxView extends View implements TabExpander,
TokenOrientedView, RSTAView { TokenOrientedView, RSTAView {
/** /**
* The default font used by the text area. If this changes we need to * The default font used by the text area. If this changes we need to
@ -70,7 +83,7 @@ public class SyntaxView extends View implements TabExpander,
private int ascent; private int ascent;
private int clipStart; private int clipStart;
private int clipEnd; private int clipEnd;
/** /**
* Temporary token used when we need to "modify" tokens for rendering * Temporary token used when we need to "modify" tokens for rendering
* purposes. Since tokens returned from RSyntaxDocuments are treated as * purposes. Since tokens returned from RSyntaxDocuments are treated as
@ -95,7 +108,7 @@ public class SyntaxView extends View implements TabExpander,
* of the element this view represents, looking for the line * of the element this view represents, looking for the line
* that is the longest. The <em>longLine</em> variable is updated to * that is the longest. The <em>longLine</em> variable is updated to
* represent the longest line contained. The <em>font</em> variable * represent the longest line contained. The <em>font</em> variable
* is updated to indicate the font used to calculate the * is updated to indicate the font used to calculate the
* longest line. * longest line.
*/ */
void calculateLongestLine() { void calculateLongestLine() {
@ -105,7 +118,7 @@ public class SyntaxView extends View implements TabExpander,
tabSize = getTabSize() * metrics.charWidth(' '); tabSize = getTabSize() * metrics.charWidth(' ');
Element lines = getElement(); Element lines = getElement();
int n = lines.getElementCount(); int n = lines.getElementCount();
for (int i=0; i<n; i++) { for (int i = 0; i < n; i++) {
Element line = lines.getElement(i); Element line = lines.getElement(i);
float w = getLineWidth(i); float w = getLineWidth(i);
if (w > longLineWidth) { if (w > longLineWidth) {
@ -121,8 +134,8 @@ public class SyntaxView extends View implements TabExpander,
* in a location that this view is responsible for. * in a location that this view is responsible for.
* *
* @param changes the change information from the associated document * @param changes the change information from the associated document
* @param a the current allocation of the view * @param a the current allocation of the view
* @param f the factory to use to rebuild if the view has children * @param f the factory to use to rebuild if the view has children
* @see View#changedUpdate * @see View#changedUpdate
*/ */
@Override @Override
@ -135,22 +148,21 @@ public class SyntaxView extends View implements TabExpander,
* Repaint the given line range. * Repaint the given line range.
* *
* @param line0 The starting line number to repaint. This must * @param line0 The starting line number to repaint. This must
* be a valid line number in the model. * be a valid line number in the model.
* @param line1 The ending line number to repaint. This must * @param line1 The ending line number to repaint. This must
* be a valid line number in the model. * be a valid line number in the model.
* @param a The region allocated for the view to render into. * @param a The region allocated for the view to render into.
* @param host The component hosting the view (used to call repaint). * @param host The component hosting the view (used to call repaint).
*/ */
protected void damageLineRange(int line0, int line1, Shape a, protected void damageLineRange(int line0, int line1, Shape a,
Component host) { Component host) {
if (a != null) { if (a != null) {
Rectangle area0 = lineToRect(a, line0); Rectangle area0 = lineToRect(a, line0);
Rectangle area1 = lineToRect(a, line1); Rectangle area1 = lineToRect(a, line1);
if ((area0 != null) && (area1 != null)) { if ((area0 != null) && (area1 != null)) {
Rectangle dmg = area0.union(area1); // damage. Rectangle dmg = area0.union(area1); // damage.
host.repaint(dmg.x, dmg.y, dmg.width, dmg.height); host.repaint(dmg.x, dmg.y, dmg.width, dmg.height);
} } else
else
host.repaint(); host.repaint();
} }
} }
@ -163,19 +175,19 @@ public class SyntaxView extends View implements TabExpander,
* off. * off.
* *
* @param painter The painter to render the tokens. * @param painter The painter to render the tokens.
* @param token The list of tokens to draw. * @param token The list of tokens to draw.
* @param g The graphics context in which to draw. * @param g The graphics context in which to draw.
* @param x The x-coordinate at which to draw. * @param x The x-coordinate at which to draw.
* @param y The y-coordinate at which to draw. * @param y The y-coordinate at which to draw.
* @return The x-coordinate representing the end of the painted text. * @return The x-coordinate representing the end of the painted text.
*/ */
private float drawLine(TokenPainter painter, Token token, Graphics2D g, private float drawLine(TokenPainter painter, Token token, Graphics2D g,
float x, float y) { float x, float y) {
float nextX = x; // The x-value at the end of our text. float nextX = x; // The x-value at the end of our text.
while (token!=null && token.isPaintable() && nextX<clipEnd) { while (token != null && token.isPaintable() && nextX < clipEnd) {
nextX = painter.paint(token, g, nextX,y, host, this, clipStart); nextX = painter.paint(token, g, nextX, y, host, this, clipStart);
token = token.getNextToken(); token = token.getNextToken();
} }
@ -198,29 +210,29 @@ public class SyntaxView extends View implements TabExpander,
* language. Tokens are checked for being in a selected region, and are * language. Tokens are checked for being in a selected region, and are
* rendered appropriately if they are. * rendered appropriately if they are.
* *
* @param painter The painter to render the tokens. * @param painter The painter to render the tokens.
* @param token The list of tokens to draw. * @param token The list of tokens to draw.
* @param g The graphics context in which to draw. * @param g The graphics context in which to draw.
* @param x The x-coordinate at which to draw. * @param x The x-coordinate at which to draw.
* @param y The y-coordinate at which to draw. * @param y The y-coordinate at which to draw.
* @param selStart The start of the selection. * @param selStart The start of the selection.
* @param selEnd The end of the selection. * @param selEnd The end of the selection.
* @return The x-coordinate representing the end of the painted text. * @return The x-coordinate representing the end of the painted text.
*/ */
private float drawLineWithSelection(TokenPainter painter, Token token, private float drawLineWithSelection(TokenPainter painter, Token token,
Graphics2D g, float x, float y, int selStart, int selEnd) { Graphics2D g, float x, float y, int selStart, int selEnd) {
float nextX = x; // The x-value at the end of our text. float nextX = x; // The x-value at the end of our text.
while (token!=null && token.isPaintable() && nextX<clipEnd) { while (token != null && token.isPaintable() && nextX < clipEnd) {
// Selection starts in this token // Selection starts in this token
if (token.containsPosition(selStart)) { if (token.containsPosition(selStart)) {
if (selStart>token.getOffset()) { if (selStart > token.getOffset()) {
tempToken.copyFrom(token); tempToken.copyFrom(token);
tempToken.textCount = selStart - tempToken.getOffset(); tempToken.textCount = selStart - tempToken.getOffset();
nextX = painter.paint(tempToken,g,nextX,y,host, this, clipStart); nextX = painter.paint(tempToken, g, nextX, y, host, this, clipStart);
tempToken.textCount = token.length(); tempToken.textCount = token.length();
tempToken.makeStartAt(selStart); tempToken.makeStartAt(selStart);
// Clone required since token and tempToken must be // Clone required since token and tempToken must be
@ -229,21 +241,20 @@ public class SyntaxView extends View implements TabExpander,
} }
int tokenLen = token.length(); int tokenLen = token.length();
int selCount = Math.min(tokenLen, selEnd-token.getOffset()); int selCount = Math.min(tokenLen, selEnd - token.getOffset());
if (selCount==tokenLen) { if (selCount == tokenLen) {
nextX = painter.paintSelected(token, g, nextX,y, host, nextX = painter.paintSelected(token, g, nextX, y, host,
this, clipStart); this, clipStart);
} } else {
else {
tempToken.copyFrom(token); tempToken.copyFrom(token);
tempToken.textCount = selCount; tempToken.textCount = selCount;
nextX = painter.paintSelected(tempToken, g, nextX,y, host, nextX = painter.paintSelected(tempToken, g, nextX, y, host,
this, clipStart); this, clipStart);
tempToken.textCount = token.length(); tempToken.textCount = token.length();
tempToken.makeStartAt(token.getOffset() + selCount); tempToken.makeStartAt(token.getOffset() + selCount);
token = tempToken; token = tempToken;
nextX = painter.paint(token, g, nextX,y, host, this, nextX = painter.paint(token, g, nextX, y, host, this,
clipStart); clipStart);
} }
} }
@ -252,24 +263,24 @@ public class SyntaxView extends View implements TabExpander,
else if (token.containsPosition(selEnd)) { else if (token.containsPosition(selEnd)) {
tempToken.copyFrom(token); tempToken.copyFrom(token);
tempToken.textCount = selEnd - tempToken.getOffset(); tempToken.textCount = selEnd - tempToken.getOffset();
nextX = painter.paintSelected(tempToken, g, nextX,y, host, this, nextX = painter.paintSelected(tempToken, g, nextX, y, host, this,
clipStart); clipStart);
tempToken.textCount = token.length(); tempToken.textCount = token.length();
tempToken.makeStartAt(selEnd); tempToken.makeStartAt(selEnd);
token = tempToken; token = tempToken;
nextX = painter.paint(token, g, nextX,y, host, this, clipStart); nextX = painter.paint(token, g, nextX, y, host, this, clipStart);
} }
// This token is entirely selected // This token is entirely selected
else if (token.getOffset()>=selStart && else if (token.getOffset() >= selStart &&
token.getEndOffset()<=selEnd) { token.getEndOffset() <= selEnd) {
nextX = painter.paintSelected(token, g, nextX,y, host, this, nextX = painter.paintSelected(token, g, nextX, y, host, this,
clipStart); clipStart);
} }
// This token is entirely unselected // This token is entirely unselected
else { else {
nextX = painter.paint(token, g, nextX,y, host, this, clipStart); nextX = painter.paint(token, g, nextX, y, host, this, clipStart);
} }
token = token.getNextToken(); token = token.getNextToken();
@ -293,42 +304,42 @@ public class SyntaxView extends View implements TabExpander,
/** /**
* Calculates the width of the line represented by the given element. * Calculates the width of the line represented by the given element.
* *
* @param line The line for which to get the length. * @param line The line for which to get the length.
* @param lineNumber The line number of the specified line in the document. * @param lineNumber The line number of the specified line in the document.
* @return The width of the line. * @return The width of the line.
*/ */
private float getLineWidth(int lineNumber) { private float getLineWidth(int lineNumber) {
Token tokenList = ((RSyntaxDocument)getDocument()). Token tokenList = ((RSyntaxDocument) getDocument()).
getTokenListForLine(lineNumber); getTokenListForLine(lineNumber);
return RSyntaxUtilities.getTokenListWidth(tokenList, return RSyntaxUtilities.getTokenListWidth(tokenList,
(RSyntaxTextArea)getContainer(), (RSyntaxTextArea) getContainer(),
this); this);
} }
/** /**
* Provides a way to determine the next visually represented model * Provides a way to determine the next visually represented model
* location that one might place a caret. Some views may not be visible, * location that one might place a caret. Some views may not be visible,
* they might not be in the same order found in the model, or they just * they might not be in the same order found in the model, or they just
* might not allow access to some of the locations in the model. * might not allow access to some of the locations in the model.
* *
* @param pos the position to convert >= 0 * @param pos the position to convert >= 0
* @param a the allocated region to render into * @param a the allocated region to render into
* @param direction the direction from the current position that can * @param direction the direction from the current position that can
* be thought of as the arrow keys typically found on a keyboard. * be thought of as the arrow keys typically found on a keyboard.
* This may be SwingConstants.WEST, SwingConstants.EAST, * This may be SwingConstants.WEST, SwingConstants.EAST,
* SwingConstants.NORTH, or SwingConstants.SOUTH. * SwingConstants.NORTH, or SwingConstants.SOUTH.
* @return the location within the model that best represents the next * @return the location within the model that best represents the next
* location visual position. * location visual position.
* @exception BadLocationException * @throws BadLocationException
* @exception IllegalArgumentException for an invalid direction * @throws IllegalArgumentException for an invalid direction
*/ */
@Override @Override
public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a,
int direction, Position.Bias[] biasRet) int direction, Position.Bias[] biasRet)
throws BadLocationException { throws BadLocationException {
return RSyntaxUtilities.getNextVisualPositionFrom(pos, b, a, return RSyntaxUtilities.getNextVisualPositionFrom(pos, b, a,
direction, biasRet, this); direction, biasRet, this);
} }
@ -337,11 +348,11 @@ public class SyntaxView extends View implements TabExpander,
* axis. * axis.
* *
* @param axis may be either View.X_AXIS or View.Y_AXIS * @param axis may be either View.X_AXIS or View.Y_AXIS
* @return the span the view would like to be rendered into >= 0. * @return the span the view would like to be rendered into >= 0.
* Typically the view is told to render into the span * Typically the view is told to render into the span
* that is returned, although there is no guarantee. * that is returned, although there is no guarantee.
* The parent may choose to resize or break the view. * The parent may choose to resize or break the view.
* @exception IllegalArgumentException for an invalid axis * @throws IllegalArgumentException for an invalid axis
*/ */
@Override @Override
public float getPreferredSpan(int axis) { public float getPreferredSpan(int axis) {
@ -357,13 +368,13 @@ public class SyntaxView extends View implements TabExpander,
// We update lineHeight here as when this method is first // We update lineHeight here as when this method is first
// called, lineHeight isn't initialized. If we don't do it // called, lineHeight isn't initialized. If we don't do it
// here, we get no vertical scrollbar (as lineHeight==0). // here, we get no vertical scrollbar (as lineHeight==0).
lineHeight = host!=null ? host.getLineHeight() : lineHeight; lineHeight = host != null ? host.getLineHeight() : lineHeight;
// return getElement().getElementCount() * lineHeight; // return getElement().getElementCount() * lineHeight;
int visibleLineCount = getElement().getElementCount(); int visibleLineCount = getElement().getElementCount();
if (host.isCodeFoldingEnabled()) { if (host.isCodeFoldingEnabled()) {
visibleLineCount -= host.getFoldManager().getHiddenLineCount(); visibleLineCount -= host.getFoldManager().getHiddenLineCount();
} }
return visibleLineCount * lineHeight; return visibleLineCount * lineHeight;
default: default:
throw new IllegalArgumentException("Invalid axis: " + axis); throw new IllegalArgumentException("Invalid axis: " + axis);
} }
@ -378,7 +389,7 @@ return visibleLineCount * lineHeight;
*/ */
private final int getRhsCorrection() { private final int getRhsCorrection() {
int rhsCorrection = 10; int rhsCorrection = 10;
if (host!=null) { if (host != null) {
rhsCorrection = host.getRightHandSideCorrection(); rhsCorrection = host.getRightHandSideCorrection();
} }
return rhsCorrection; return rhsCorrection;
@ -391,8 +402,8 @@ return visibleLineCount * lineHeight;
* @return The tab size. * @return The tab size.
*/ */
private int getTabSize() { private int getTabSize() {
Integer i = (Integer)getDocument().getProperty( Integer i = (Integer) getDocument().getProperty(
PlainDocument.tabSizeAttribute); PlainDocument.tabSizeAttribute);
int size = (i != null) ? i.intValue() : 5; int size = (i != null) ? i.intValue() : 5;
return size; return size;
} }
@ -407,26 +418,25 @@ return visibleLineCount * lineHeight;
* *
* @param offset The offset in question. * @param offset The offset in question.
* @return A token list for the physical (and in this view, logical) line * @return A token list for the physical (and in this view, logical) line
* before this one. If <code>offset</code> is in the first line in * before this one. If <code>offset</code> is in the first line in
* the document, <code>null</code> is returned. * the document, <code>null</code> is returned.
*/ */
public Token getTokenListForPhysicalLineAbove(int offset) { public Token getTokenListForPhysicalLineAbove(int offset) {
RSyntaxDocument document = (RSyntaxDocument)getDocument(); RSyntaxDocument document = (RSyntaxDocument) getDocument();
Element map = document.getDefaultRootElement(); Element map = document.getDefaultRootElement();
int line = map.getElementIndex(offset); int line = map.getElementIndex(offset);
FoldManager fm = host.getFoldManager(); FoldManager fm = host.getFoldManager();
if (fm==null) { if (fm == null) {
line--; line--;
if (line>=0) { if (line >= 0) {
return document.getTokenListForLine(line); return document.getTokenListForLine(line);
} }
} } else {
else { line = fm.getVisibleLineAbove(line);
line = fm.getVisibleLineAbove(line); if (line >= 0) {
if (line>=0) { return document.getTokenListForLine(line);
return document.getTokenListForLine(line); }
} }
}
// int line = map.getElementIndex(offset) - 1; // int line = map.getElementIndex(offset) - 1;
// if (line>=0) // if (line>=0)
// return document.getTokenListForLine(line); // return document.getTokenListForLine(line);
@ -443,26 +453,25 @@ else {
* *
* @param offset The offset in question. * @param offset The offset in question.
* @return A token list for the physical (and in this view, logical) line * @return A token list for the physical (and in this view, logical) line
* after this one. If <code>offset</code> is in the last physical * after this one. If <code>offset</code> is in the last physical
* line in the document, <code>null</code> is returned. * line in the document, <code>null</code> is returned.
*/ */
public Token getTokenListForPhysicalLineBelow(int offset) { public Token getTokenListForPhysicalLineBelow(int offset) {
RSyntaxDocument document = (RSyntaxDocument)getDocument(); RSyntaxDocument document = (RSyntaxDocument) getDocument();
Element map = document.getDefaultRootElement(); Element map = document.getDefaultRootElement();
int lineCount = map.getElementCount(); int lineCount = map.getElementCount();
int line = map.getElementIndex(offset); int line = map.getElementIndex(offset);
if (!host.isCodeFoldingEnabled()) { if (!host.isCodeFoldingEnabled()) {
if (line<lineCount-1) { if (line < lineCount - 1) {
return document.getTokenListForLine(line+1); return document.getTokenListForLine(line + 1);
} }
} } else {
else { FoldManager fm = host.getFoldManager();
FoldManager fm = host.getFoldManager(); line = fm.getVisibleLineBelow(line);
line = fm.getVisibleLineBelow(line); if (line >= 0 && line < lineCount) {
if (line>=0 && line<lineCount) { return document.getTokenListForLine(line);
return document.getTokenListForLine(line); }
} }
}
// int line = map.getElementIndex(offset); // int line = map.getElementIndex(offset);
// int lineCount = map.getElementCount(); // int lineCount = map.getElementCount();
// if (line<lineCount-1) // if (line<lineCount-1)
@ -476,8 +485,8 @@ else {
* in a location that this view is responsible for. * in a location that this view is responsible for.
* *
* @param changes The change information from the associated document. * @param changes The change information from the associated document.
* @param a The current allocation of the view. * @param a The current allocation of the view.
* @param f The factory to use to rebuild if the view has children. * @param f The factory to use to rebuild if the view has children.
*/ */
@Override @Override
public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f) { public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
@ -488,9 +497,9 @@ else {
/** /**
* Determine the rectangle that represents the given line. * Determine the rectangle that represents the given line.
* *
* @param a The region allocated for the view to render into * @param a The region allocated for the view to render into
* @param line The line number to find the region of. This must * @param line The line number to find the region of. This must
* be a valid line number in the model. * be a valid line number in the model.
*/ */
protected Rectangle lineToRect(Shape a, int line) { protected Rectangle lineToRect(Shape a, int line) {
Rectangle r = null; Rectangle r = null;
@ -500,14 +509,14 @@ else {
// NOTE: lineHeight is not initially set here, leading to the // NOTE: lineHeight is not initially set here, leading to the
// current line not being highlighted when a document is first // current line not being highlighted when a document is first
// opened. So, we set it here just in case. // opened. So, we set it here just in case.
lineHeight = host!=null ? host.getLineHeight() : lineHeight; lineHeight = host != null ? host.getLineHeight() : lineHeight;
if (host.isCodeFoldingEnabled()) { if (host != null && host.isCodeFoldingEnabled()) {
FoldManager fm = host.getFoldManager(); FoldManager fm = host.getFoldManager();
int hiddenCount = fm.getHiddenLineCountAbove(line); int hiddenCount = fm.getHiddenLineCountAbove(line);
line -= hiddenCount; line -= hiddenCount;
} }
r = new Rectangle(alloc.x, alloc.y + line*lineHeight, r = new Rectangle(alloc.x, alloc.y + line * lineHeight,
alloc.width, lineHeight); alloc.width, lineHeight);
} }
return r; return r;
} }
@ -518,19 +527,19 @@ if (host.isCodeFoldingEnabled()) {
* to the coordinate space of the view mapped to it. * to the coordinate space of the view mapped to it.
* *
* @param pos the position to convert >= 0 * @param pos the position to convert >= 0
* @param a the allocated region to render into * @param a the allocated region to render into
* @return the bounding box of the given position * @return the bounding box of the given position
* @exception BadLocationException if the given position does not * @throws BadLocationException if the given position does not
* represent a valid location in the associated document * represent a valid location in the associated document
* @see View#modelToView * @see View#modelToView
*/ */
@Override @Override
public Shape modelToView(int pos, Shape a, Position.Bias b) public Shape modelToView(int pos, Shape a, Position.Bias b)
throws BadLocationException { throws BadLocationException {
// line coordinates // line coordinates
Element map = getElement(); Element map = getElement();
RSyntaxDocument doc = (RSyntaxDocument)getDocument(); RSyntaxDocument doc = (RSyntaxDocument) getDocument();
int lineIndex = map.getElementIndex(pos); int lineIndex = map.getElementIndex(pos);
Token tokenList = doc.getTokenListForLine(lineIndex); Token tokenList = doc.getTokenListForLine(lineIndex);
Rectangle lineArea = lineToRect(a, lineIndex); Rectangle lineArea = lineToRect(a, lineIndex);
@ -542,8 +551,8 @@ if (host.isCodeFoldingEnabled()) {
// We use this method instead as it returns the actual bounding box, // We use this method instead as it returns the actual bounding box,
// not just the x-coordinate. // not just the x-coordinate.
lineArea = tokenList.listOffsetToView( lineArea = tokenList.listOffsetToView(
(RSyntaxTextArea)getContainer(), this, pos, (RSyntaxTextArea) getContainer(), this, pos,
tabBase, lineArea); tabBase, lineArea);
return lineArea; return lineArea;
@ -554,7 +563,7 @@ if (host.isCodeFoldingEnabled()) {
* Provides a mapping, for a given region, from the document model * Provides a mapping, for a given region, from the document model
* coordinate space to the view coordinate space. The specified region is * coordinate space to the view coordinate space. The specified region is
* created as a union of the first and last character positions.<p> * created as a union of the first and last character positions.<p>
* * <p>
* This is implemented to subtract the width of the second character, as * This is implemented to subtract the width of the second character, as
* this view's <code>modelToView</code> actually returns the width of the * this view's <code>modelToView</code> actually returns the width of the
* character instead of "1" or "0" like the View implementations in * character instead of "1" or "0" like the View implementations in
@ -565,34 +574,34 @@ if (host.isCodeFoldingEnabled()) {
* *
* @param p0 the position of the first character (>=0) * @param p0 the position of the first character (>=0)
* @param b0 The bias of the first character position, toward the previous * @param b0 The bias of the first character position, toward the previous
* character or the next character represented by the offset, in * character or the next character represented by the offset, in
* case the position is a boundary of two views; <code>b0</code> * case the position is a boundary of two views; <code>b0</code>
* will have one of these values: * will have one of these values:
* <ul> * <ul>
* <li> <code>Position.Bias.Forward</code> * <li> <code>Position.Bias.Forward</code>
* <li> <code>Position.Bias.Backward</code> * <li> <code>Position.Bias.Backward</code>
* </ul> * </ul>
* @param p1 the position of the last character (>=0) * @param p1 the position of the last character (>=0)
* @param b1 the bias for the second character position, defined * @param b1 the bias for the second character position, defined
* one of the legal values shown above * one of the legal values shown above
* @param a the area of the view, which encompasses the requested region * @param a the area of the view, which encompasses the requested region
* @return the bounding box which is a union of the region specified * @return the bounding box which is a union of the region specified
* by the first and last character positions * by the first and last character positions
* @exception BadLocationException if the given position does * @throws BadLocationException if the given position does
* not represent a valid location in the associated document * not represent a valid location in the associated document
* @exception IllegalArgumentException if <code>b0</code> or * @throws IllegalArgumentException if <code>b0</code> or
* <code>b1</code> are not one of the * <code>b1</code> are not one of the
* legal <code>Position.Bias</code> values listed above * legal <code>Position.Bias</code> values listed above
* @see View#viewToModel * @see View#viewToModel
*/ */
@Override @Override
public Shape modelToView(int p0, Position.Bias b0, public Shape modelToView(int p0, Position.Bias b0,
int p1, Position.Bias b1, int p1, Position.Bias b1,
Shape a) throws BadLocationException { Shape a) throws BadLocationException {
Shape s0 = modelToView(p0, a, b0); Shape s0 = modelToView(p0, a, b0);
Shape s1; Shape s1;
if (p1 ==getEndOffset()) { if (p1 == getEndOffset()) {
try { try {
s1 = modelToView(p1, a, b1); s1 = modelToView(p1, a, b1);
} catch (BadLocationException ble) { } catch (BadLocationException ble) {
@ -600,21 +609,20 @@ if (host.isCodeFoldingEnabled()) {
} }
if (s1 == null) { if (s1 == null) {
// Assume extends left to right. // Assume extends left to right.
Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : Rectangle alloc = (a instanceof Rectangle) ? (Rectangle) a :
a.getBounds(); a.getBounds();
s1 = new Rectangle(alloc.x + alloc.width - 1, alloc.y, s1 = new Rectangle(alloc.x + alloc.width - 1, alloc.y,
1, alloc.height); 1, alloc.height);
} }
} } else {
else {
s1 = modelToView(p1, a, b1); s1 = modelToView(p1, a, b1);
} }
Rectangle r0 = s0 instanceof Rectangle ? (Rectangle)s0 : s0.getBounds(); Rectangle r0 = s0 instanceof Rectangle ? (Rectangle) s0 : s0.getBounds();
Rectangle r1 = s1 instanceof Rectangle ? (Rectangle)s1 : s1.getBounds(); Rectangle r1 = s1 instanceof Rectangle ? (Rectangle) s1 : s1.getBounds();
if (r0.y != r1.y) { if (r0.y != r1.y) {
// If it spans lines, force it to be the width of the view. // If it spans lines, force it to be the width of the view.
Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : Rectangle alloc = (a instanceof Rectangle) ? (Rectangle) a :
a.getBounds(); a.getBounds();
r0.x = alloc.x; r0.x = alloc.x;
r0.width = alloc.width; r0.width = alloc.width;
} }
@ -627,7 +635,7 @@ if (host.isCodeFoldingEnabled()) {
// this, one character too many is highlighted thanks to our // this, one character too many is highlighted thanks to our
// modelToView() implementation returning the actual width of the // modelToView() implementation returning the actual width of the
// character requested! // character requested!
if (p1>p0) r0.width -= r1.width; if (p1 > p0) r0.width -= r1.width;
return r0; return r0;
@ -639,15 +647,15 @@ if (host.isCodeFoldingEnabled()) {
* This implementation does not support things like centering so it * This implementation does not support things like centering so it
* ignores the tabOffset argument. * ignores the tabOffset argument.
* *
* @param x the current position >= 0 * @param x the current position >= 0
* @param tabOffset the position within the text stream * @param tabOffset the position within the text stream
* that the tab occurred at >= 0. * that the tab occurred at >= 0.
* @return the tab stop, measured in points >= 0 * @return the tab stop, measured in points >= 0
*/ */
public float nextTabStop(float x, int tabOffset) { public float nextTabStop(float x, int tabOffset) {
if (tabSize == 0) if (tabSize == 0)
return x; return x;
int ntabs = (((int)x) - tabBase) / tabSize; int ntabs = (((int) x) - tabBase) / tabSize;
return tabBase + ((ntabs + 1) * tabSize); return tabBase + ((ntabs + 1) * tabSize);
} }
@ -662,12 +670,12 @@ if (host.isCodeFoldingEnabled()) {
@Override @Override
public void paint(Graphics g, Shape a) { public void paint(Graphics g, Shape a) {
RSyntaxDocument document = (RSyntaxDocument)getDocument(); RSyntaxDocument document = (RSyntaxDocument) getDocument();
Rectangle alloc = a.getBounds(); Rectangle alloc = a.getBounds();
tabBase = alloc.x; tabBase = alloc.x;
host = (RSyntaxTextArea)getContainer(); host = (RSyntaxTextArea) getContainer();
Rectangle clip = g.getClipBounds(); Rectangle clip = g.getClipBounds();
// An attempt to speed things up for files with long lines. Note that // An attempt to speed things up for files with long lines. Note that
@ -695,52 +703,51 @@ if (host.isCodeFoldingEnabled()) {
boolean useSelectedTextColor = host.getUseSelectedTextColor(); boolean useSelectedTextColor = host.getUseSelectedTextColor();
RSyntaxTextAreaHighlighter h = RSyntaxTextAreaHighlighter h =
(RSyntaxTextAreaHighlighter)host.getHighlighter(); (RSyntaxTextAreaHighlighter) host.getHighlighter();
Graphics2D g2d = (Graphics2D)g; Graphics2D g2d = (Graphics2D) g;
Token token; Token token;
//System.err.println("Painting lines: " + linesAbove + " to " + (endLine-1)); //System.err.println("Painting lines: " + linesAbove + " to " + (endLine-1));
TokenPainter painter = host.getTokenPainter(); TokenPainter painter = host.getTokenPainter();
int line = linesAbove; int line = linesAbove;
//int count = 0; //int count = 0;
while (y<clip.y+clip.height+ascent && line<lineCount) { while (y < clip.y + clip.height + ascent && line < lineCount) {
Fold fold = fm.getFoldForLine(line); Fold fold = fm.getFoldForLine(line);
Element lineElement = map.getElement(line); Element lineElement = map.getElement(line);
int startOffset = lineElement.getStartOffset(); int startOffset = lineElement.getStartOffset();
//int endOffset = (line==lineCount ? lineElement.getEndOffset()-1 : //int endOffset = (line==lineCount ? lineElement.getEndOffset()-1 :
// lineElement.getEndOffset()-1); // lineElement.getEndOffset()-1);
int endOffset = lineElement.getEndOffset()-1; // Why always "-1"? int endOffset = lineElement.getEndOffset() - 1; // Why always "-1"?
h.paintLayeredHighlights(g2d, startOffset, endOffset, h.paintLayeredHighlights(g2d, startOffset, endOffset,
a, host, this); a, host, this);
// Paint a line of text. // Paint a line of text.
token = document.getTokenListForLine(line); token = document.getTokenListForLine(line);
if (!useSelectedTextColor || selStart==selEnd || if (!useSelectedTextColor || selStart == selEnd ||
(startOffset>=selEnd || endOffset<selStart)) { (startOffset >= selEnd || endOffset < selStart)) {
drawLine(painter, token, g2d, x,y); drawLine(painter, token, g2d, x, y);
} } else {
else {
//System.out.println("Drawing line with selection: " + line); //System.out.println("Drawing line with selection: " + line);
drawLineWithSelection(painter,token,g2d, x,y, selStart, selEnd); drawLineWithSelection(painter, token, g2d, x, y, selStart, selEnd);
} }
if (fold!=null && fold.isCollapsed()) { if (fold != null && fold.isCollapsed()) {
// Visible indicator of collapsed lines // Visible indicator of collapsed lines
Color c = RSyntaxUtilities.getFoldedLineBottomColor(host); Color c = RSyntaxUtilities.getFoldedLineBottomColor(host);
if (c!=null) { if (c != null) {
g.setColor(c); g.setColor(c);
g.drawLine(x,y+lineHeight-ascent-1, g.drawLine(x, y + lineHeight - ascent - 1,
alloc.width,y+lineHeight-ascent-1); alloc.width, y + lineHeight - ascent - 1);
} }
// Skip to next line to paint, taking extra care for lines with // Skip to next line to paint, taking extra care for lines with
// block ends and begins together, e.g. "} else {" // block ends and begins together, e.g. "} else {"
do { do {
int hiddenLineCount = fold.getLineCount(); int hiddenLineCount = fold.getLineCount();
if (hiddenLineCount==0) { if (hiddenLineCount == 0) {
// Fold parser identified a zero-line fold region. // Fold parser identified a zero-line fold region.
// This is really a bug, but we'll be graceful here // This is really a bug, but we'll be graceful here
// and avoid an infinite loop. // and avoid an infinite loop.
@ -748,7 +755,7 @@ if (host.isCodeFoldingEnabled()) {
} }
line += hiddenLineCount; line += hiddenLineCount;
fold = fm.getFoldForLine(line); fold = fm.getFoldForLine(line);
} while (fold!=null && fold.isCollapsed()); } while (fold != null && fold.isCollapsed());
} }
@ -767,7 +774,7 @@ if (host.isCodeFoldingEnabled()) {
* If the passed-in line is longer than the current longest line, then * If the passed-in line is longer than the current longest line, then
* the longest line is updated. * the longest line is updated.
* *
* @param line The line to test against the current longest. * @param line The line to test against the current longest.
* @param lineNumber The line number of the passed-in line. * @param lineNumber The line number of the passed-in line.
* @return <code>true</code> iff the current longest line was updated. * @return <code>true</code> iff the current longest line was updated.
*/ */
@ -787,8 +794,8 @@ if (host.isCodeFoldingEnabled()) {
* in a location that this view is responsible for. * in a location that this view is responsible for.
* *
* @param changes the change information from the associated document * @param changes the change information from the associated document
* @param a the current allocation of the view * @param a the current allocation of the view
* @param f the factory to use to rebuild if the view has children * @param f the factory to use to rebuild if the view has children
*/ */
@Override @Override
public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory f) { public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
@ -806,9 +813,9 @@ if (host.isCodeFoldingEnabled()) {
/** /**
* Repaint the region of change covered by the given document * Repaint the region of change covered by the given document
* event. Damages the line that begins the range to cover * event. Damages the line that begins the range to cover
* the case when the insert/remove is only on one line. * the case when the insert/remove is only on one line.
* If lines are added or removed, damages the whole * If lines are added or removed, damages the whole
* view. The longest line is checked to see if it has * view. The longest line is checked to see if it has
* changed. * changed.
*/ */
protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f) { protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f) {
@ -818,13 +825,13 @@ if (host.isCodeFoldingEnabled()) {
DocumentEvent.ElementChange ec = changes.getChange(elem); DocumentEvent.ElementChange ec = changes.getChange(elem);
Element[] added = (ec != null) ? ec.getChildrenAdded() : null; Element[] added = (ec != null) ? ec.getChildrenAdded() : null;
Element[] removed = (ec != null) ? ec.getChildrenRemoved() : null; Element[] removed = (ec != null) ? ec.getChildrenRemoved() : null;
if (((added != null) && (added.length > 0)) || if (((added != null) && (added.length > 0)) ||
((removed != null) && (removed.length > 0))) { ((removed != null) && (removed.length > 0))) {
// lines were added or removed... // lines were added or removed...
if (added != null) { if (added != null) {
int addedAt = ec.getIndex(); // FIXME: Is this correct????? int addedAt = ec.getIndex(); // FIXME: Is this correct?????
for (int i = 0; i < added.length; i++) for (int i = 0; i < added.length; i++)
possiblyUpdateLongLine(added[i], addedAt+i); possiblyUpdateLongLine(added[i], addedAt + i);
} }
if (removed != null) { if (removed != null) {
for (int i = 0; i < removed.length; i++) { for (int i = 0; i < removed.length; i++) {
@ -841,14 +848,12 @@ if (host.isCodeFoldingEnabled()) {
// This occurs when syntax highlighting only changes on lines // This occurs when syntax highlighting only changes on lines
// (i.e. beginning a multiline comment). // (i.e. beginning a multiline comment).
else if (changes.getType()==DocumentEvent.EventType.CHANGE) { else if (changes.getType() == DocumentEvent.EventType.CHANGE) {
//System.err.println("Updating the damage due to a CHANGE event..."); //System.err.println("Updating the damage due to a CHANGE event...");
int startLine = changes.getOffset(); int startLine = changes.getOffset();
int endLine = changes.getLength(); int endLine = changes.getLength();
damageLineRange(startLine,endLine, a, host); damageLineRange(startLine, endLine, a, host);
} } else {
else {
Element map = getElement(); Element map = getElement();
int line = map.getElementIndex(changes.getOffset()); int line = map.getElementIndex(changes.getOffset());
damageLineRange(line, line, a, host); damageLineRange(line, line, a, host);
@ -861,20 +866,18 @@ if (host.isCodeFoldingEnabled()) {
// because it has gotten longer. // because it has gotten longer.
longLineWidth = getLineWidth(line); longLineWidth = getLineWidth(line);
preferenceChanged(null, true, false); preferenceChanged(null, true, false);
} } else {
else {
// If long line gets updated, update the status bars too. // If long line gets updated, update the status bars too.
if (possiblyUpdateLongLine(e, line)) if (possiblyUpdateLongLine(e, line))
preferenceChanged(null, true, false); preferenceChanged(null, true, false);
} }
} } else if (changes.getType() == DocumentEvent.EventType.REMOVE) {
else if (changes.getType() == DocumentEvent.EventType.REMOVE) {
if (map.getElement(line) == longLine) { if (map.getElement(line) == longLine) {
// removed from longest line... recalc // removed from longest line... recalc
longLineWidth = -1; // Must do this! longLineWidth = -1; // Must do this!
calculateLongestLine(); calculateLongestLine();
preferenceChanged(null, true, false); preferenceChanged(null, true, false);
} }
} }
} }
} }
@ -884,7 +887,7 @@ if (host.isCodeFoldingEnabled()) {
* Checks to see if the font metrics and longest line are up-to-date. * Checks to see if the font metrics and longest line are up-to-date.
*/ */
private void updateMetrics() { private void updateMetrics() {
host = (RSyntaxTextArea)getContainer(); host = (RSyntaxTextArea) getContainer();
Font f = host.getFont(); Font f = host.getFont();
if (font != f) { if (font != f) {
// The font changed, we need to recalculate the longest line! // The font changed, we need to recalculate the longest line!
@ -900,9 +903,9 @@ if (host.isCodeFoldingEnabled()) {
* *
* @param fx the X coordinate >= 0 * @param fx the X coordinate >= 0
* @param fy the Y coordinate >= 0 * @param fy the Y coordinate >= 0
* @param a the allocated region to render into * @param a the allocated region to render into
* @return the location within the model that best represents the * @return the location within the model that best represents the
* given point in the view >= 0 * given point in the view >= 0
*/ */
@Override @Override
public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) { public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) {
@ -910,7 +913,7 @@ if (host.isCodeFoldingEnabled()) {
bias[0] = Position.Bias.Forward; bias[0] = Position.Bias.Forward;
Rectangle alloc = a.getBounds(); Rectangle alloc = a.getBounds();
RSyntaxDocument doc = (RSyntaxDocument)getDocument(); RSyntaxDocument doc = (RSyntaxDocument) getDocument();
int x = (int) fx; int x = (int) fx;
int y = (int) fy; int y = (int) fy;
@ -936,9 +939,9 @@ if (host.isCodeFoldingEnabled()) {
Element map = doc.getDefaultRootElement(); Element map = doc.getDefaultRootElement();
int lineIndex = Math.abs((y - alloc.y) / lineHeight);//metrics.getHeight() ); int lineIndex = Math.abs((y - alloc.y) / lineHeight);//metrics.getHeight() );
FoldManager fm = host.getFoldManager(); FoldManager fm = host.getFoldManager();
//System.out.print("--- " + lineIndex); //System.out.print("--- " + lineIndex);
lineIndex += fm.getHiddenLineCountAbove(lineIndex, true); lineIndex += fm.getHiddenLineCountAbove(lineIndex, true);
//System.out.println(" => " + lineIndex); //System.out.println(" => " + lineIndex);
if (lineIndex >= map.getElementCount()) { if (lineIndex >= map.getElementCount()) {
return host.getLastVisibleOffset(); return host.getLastVisibleOffset();
@ -950,7 +953,7 @@ lineIndex += fm.getHiddenLineCountAbove(lineIndex, true);
if (x < alloc.x) if (x < alloc.x)
return line.getStartOffset(); return line.getStartOffset();
// If the point is to the right of the line... // If the point is to the right of the line...
else if (x > alloc.x + alloc.width) else if (x > alloc.x + alloc.width)
return line.getEndOffset() - 1; return line.getEndOffset() - 1;
@ -960,14 +963,14 @@ lineIndex += fm.getHiddenLineCountAbove(lineIndex, true);
Token tokenList = doc.getTokenListForLine(lineIndex); Token tokenList = doc.getTokenListForLine(lineIndex);
tabBase = alloc.x; tabBase = alloc.x;
int offs = tokenList.getListOffset( int offs = tokenList.getListOffset(
(RSyntaxTextArea)getContainer(), (RSyntaxTextArea) getContainer(),
this, tabBase, x); this, tabBase, x);
return offs!=-1 ? offs : p0; return offs != -1 ? offs : p0;
} }
} // End of else. } // End of else.
} }
/** /**
@ -981,11 +984,13 @@ lineIndex += fm.getHiddenLineCountAbove(lineIndex, true);
// NOTE: lineHeight is not initially set here, leading to the // NOTE: lineHeight is not initially set here, leading to the
// current line not being highlighted when a document is first // current line not being highlighted when a document is first
// opened. So, we set it here just in case. // opened. So, we set it here just in case.
lineHeight = host!=null ? host.getLineHeight() : lineHeight; lineHeight = host != null ? host.getLineHeight() : lineHeight;
FoldManager fm = host.getFoldManager(); if (host != null) {
if (!fm.isLineHidden(line)) { FoldManager fm = host.getFoldManager();
line -= fm.getHiddenLineCountAbove(line); if (!fm.isLineHidden(line)) {
return alloc.y + line*lineHeight; line -= fm.getHiddenLineCountAbove(line);
return alloc.y + line * lineHeight;
}
} }
} }
@ -998,7 +1003,7 @@ lineIndex += fm.getHiddenLineCountAbove(lineIndex, true);
* {@inheritDoc} * {@inheritDoc}
*/ */
public int yForLineContaining(Rectangle alloc, int offs) public int yForLineContaining(Rectangle alloc, int offs)
throws BadLocationException { throws BadLocationException {
Element map = getElement(); Element map = getElement();
int line = map.getElementIndex(offs); int line = map.getElementIndex(offs);
return yForLine(alloc, line); return yForLine(alloc, line);

145
designer-base/src/main/java/com/fr/design/gui/syntax/ui/rsyntaxtextarea/WrappedSyntaxView.java

@ -3,21 +3,39 @@
* *
* WrappedSyntaxView.java - Test implementation of WrappedSyntaxView that * WrappedSyntaxView.java - Test implementation of WrappedSyntaxView that
* is also aware of RSyntaxTextArea's different fonts per token type. * is also aware of RSyntaxTextArea's different fonts per token type.
* *
* This library is distributed under a modified BSD license. See the included * This library is distributed under a modified BSD license. See the included
* RSyntaxTextArea.License.txt file for details. * RSyntaxTextArea.License.txt file for details.
*/ */
package com.fr.design.gui.syntax.ui.rsyntaxtextarea; package com.fr.design.gui.syntax.ui.rsyntaxtextarea;
import java.awt.*;
import javax.swing.text.*;
import javax.swing.text.Position.Bias;
import javax.swing.event.*;
import com.fr.design.gui.syntax.ui.rsyntaxtextarea.TokenUtils.TokenSubList; import com.fr.design.gui.syntax.ui.rsyntaxtextarea.TokenUtils.TokenSubList;
import com.fr.design.gui.syntax.ui.rsyntaxtextarea.folding.Fold; import com.fr.design.gui.syntax.ui.rsyntaxtextarea.folding.Fold;
import com.fr.design.gui.syntax.ui.rsyntaxtextarea.folding.FoldManager; import com.fr.design.gui.syntax.ui.rsyntaxtextarea.folding.FoldManager;
import com.fr.design.gui.syntax.ui.rtextarea.Gutter; import com.fr.design.gui.syntax.ui.rtextarea.Gutter;
import com.fr.stable.CommonUtils;
import javax.swing.event.DocumentEvent;
import javax.swing.text.BadLocationException;
import javax.swing.text.BoxView;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.LayeredHighlighter;
import javax.swing.text.PlainDocument;
import javax.swing.text.Position;
import javax.swing.text.Position.Bias;
import javax.swing.text.Segment;
import javax.swing.text.TabExpander;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
/** /**
@ -27,17 +45,17 @@ import com.fr.design.gui.syntax.ui.rtextarea.Gutter;
* @version 0.2 * @version 0.2
*/ */
public class WrappedSyntaxView extends BoxView implements TabExpander, public class WrappedSyntaxView extends BoxView implements TabExpander,
RSTAView { RSTAView {
boolean widthChanging; boolean widthChanging;
int tabBase; int tabBase;
int tabSize; int tabSize;
/** /**
* This is reused to keep from allocating/deallocating. * This is reused to keep from allocating/deallocating.
*/ */
private Segment s, drawSeg; private Segment s, drawSeg;
/** /**
* Another variable initialized once to keep from allocating/deallocating. * Another variable initialized once to keep from allocating/deallocating.
*/ */
@ -93,7 +111,7 @@ public class WrappedSyntaxView extends BoxView implements TabExpander,
int p = p0; int p = p0;
RSyntaxTextArea textArea = (RSyntaxTextArea)getContainer(); RSyntaxTextArea textArea = (RSyntaxTextArea)getContainer();
float currentWidth = getWidth(); float currentWidth = getWidth();
if (currentWidth==Integer.MAX_VALUE) if (CommonUtils.equals(currentWidth, Integer.MAX_VALUE))
currentWidth = getPreferredSpan(X_AXIS); currentWidth = getPreferredSpan(X_AXIS);
// Make sure width>0; this is a huge hack to fix a bug where // Make sure width>0; this is a huge hack to fix a bug where
// loading text into an RTextArea before it is visible if word wrap // loading text into an RTextArea before it is visible if word wrap
@ -128,7 +146,7 @@ public class WrappedSyntaxView extends BoxView implements TabExpander,
//System.err.println("------ ending calculateBreakPosition() --------"); //System.err.println("------ ending calculateBreakPosition() --------");
// return p; // return p;
return p + 1; return p + 1;
} }
//private int getBreakLocation(Token t, FontMetrics fm, int x0, int x, //private int getBreakLocation(Token t, FontMetrics fm, int x0, int x,
@ -229,7 +247,7 @@ return p + 1;
x = painter.paint(token, g, x,y, host, this); x = painter.paint(token, g, x,y, host, this);
token = token.getNextToken(); token = token.getNextToken();
} }
if (token!=null && token.isPaintable() && token.getOffset()<p) { if (token!=null && token.isPaintable() && token.getOffset()<p) {
int tokenOffset = token.getOffset(); int tokenOffset = token.getOffset();
tempToken.set(drawSeg.array, tokenOffset-start, p-1-start, tempToken.set(drawSeg.array, tokenOffset-start, p-1-start,
@ -242,7 +260,7 @@ return p + 1;
p0 = (p==p0) ? p1 : p; p0 = (p==p0) ? p1 : p;
y += fontHeight; y += fontHeight;
} // End of while (token!=null && token.isPaintable()). } // End of while (token!=null && token.isPaintable()).
// NOTE: We should re-use code from Token (paintBackground()) here, // NOTE: We should re-use code from Token (paintBackground()) here,
@ -271,8 +289,8 @@ return p + 1;
* @param selEnd The end of the selection. * @param selEnd The end of the selection.
*/ */
protected void drawViewWithSelection(TokenPainter painter, Graphics2D g, protected void drawViewWithSelection(TokenPainter painter, Graphics2D g,
Rectangle r, View view, int fontHeight, int y, int selStart, Rectangle r, View view, int fontHeight, int y, int selStart,
int selEnd) { int selEnd) {
float x = r.x; float x = r.x;
@ -371,7 +389,7 @@ return p + 1;
int tokenOffset = token.getOffset(); int tokenOffset = token.getOffset();
Token orig = token; Token orig = token;
token = new TokenImpl(drawSeg, tokenOffset-start, p-1-start, token = new TokenImpl(drawSeg, tokenOffset-start, p-1-start,
tokenOffset, token.getType()); tokenOffset, token.getType());
// Selection starts in this token // Selection starts in this token
if (token.containsPosition(selStart)) { if (token.containsPosition(selStart)) {
@ -432,7 +450,7 @@ return p + 1;
p0 = (p==p0) ? p1 : p; p0 = (p==p0) ? p1 : p;
y += fontHeight; y += fontHeight;
} // End of while (token!=null && token.isPaintable()). } // End of while (token!=null && token.isPaintable()).
// NOTE: We should re-use code from Token (paintBackground()) here, // NOTE: We should re-use code from Token (paintBackground()) here,
@ -449,7 +467,7 @@ return p + 1;
/** /**
* Fetches the allocation for the given child view.<p> * Fetches the allocation for the given child view.<p>
* Overridden to account for code folding. * Overridden to account for code folding.
* *
* @param index The index of the child, >= 0 && < getViewCount(). * @param index The index of the child, >= 0 && < getViewCount().
* @param a The allocation to this view * @param a The allocation to this view
* @return The allocation to the child; or <code>null</code> if * @return The allocation to the child; or <code>null</code> if
@ -476,7 +494,7 @@ return p + 1;
/** /**
* Fetches the allocation for the given child view to render into.<p> * Fetches the allocation for the given child view to render into.<p>
* Overridden to account for lines hidden by collapsed folded regions. * Overridden to account for lines hidden by collapsed folded regions.
* *
* @param line The index of the child, >= 0 && < getViewCount() * @param line The index of the child, >= 0 && < getViewCount()
* @param a The allocation to this view * @param a The allocation to this view
* @return The allocation to the child * @return The allocation to the child
@ -515,7 +533,7 @@ return p + 1;
* @param axis may be either View.X_AXIS or View.Y_AXIS * @param axis may be either View.X_AXIS or View.Y_AXIS
* @return the span the view would like to be rendered into. * @return the span the view would like to be rendered into.
* Typically the view is told to render into the span * Typically the view is told to render into the span
* that is returned, although there is no guarantee. * that is returned, although there is no guarantee.
* The parent may choose to resize or break the view. * The parent may choose to resize or break the view.
* @see View#getMaximumSpan * @see View#getMaximumSpan
*/ */
@ -541,7 +559,7 @@ return p + 1;
* @param axis may be either View.X_AXIS or View.Y_AXIS * @param axis may be either View.X_AXIS or View.Y_AXIS
* @return the span the view would like to be rendered into. * @return the span the view would like to be rendered into.
* Typically the view is told to render into the span * Typically the view is told to render into the span
* that is returned, although there is no guarantee. * that is returned, although there is no guarantee.
* The parent may choose to resize or break the view. * The parent may choose to resize or break the view.
* @see View#getMinimumSpan * @see View#getMinimumSpan
*/ */
@ -567,7 +585,7 @@ return p + 1;
* @param axis may be either View.X_AXIS or View.Y_AXIS * @param axis may be either View.X_AXIS or View.Y_AXIS
* @return the span the view would like to be rendered into. * @return the span the view would like to be rendered into.
* Typically the view is told to render into the span * Typically the view is told to render into the span
* that is returned, although there is no guarantee. * that is returned, although there is no guarantee.
* The parent may choose to resize or break the view. * The parent may choose to resize or break the view.
* @see View#getPreferredSpan * @see View#getPreferredSpan
*/ */
@ -605,7 +623,7 @@ return p + 1;
*/ */
protected int getTabSize() { protected int getTabSize() {
Integer i = (Integer) getDocument(). Integer i = (Integer) getDocument().
getProperty(PlainDocument.tabSizeAttribute); getProperty(PlainDocument.tabSizeAttribute);
int size = (i != null) ? i.intValue() : 5; int size = (i != null) ? i.intValue() : 5;
return size; return size;
} }
@ -643,7 +661,7 @@ return p + 1;
/** /**
* Gives notification that something was inserted into the * Gives notification that something was inserted into the
* document in a location that this view is responsible for. * document in a location that this view is responsible for.
* This is implemented to simply update the children. * This is implemented to simply update the children.
* *
@ -655,8 +673,8 @@ return p + 1;
@Override @Override
public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f) { public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
updateChildren(changes, a); updateChildren(changes, a);
Rectangle alloc = ((a != null) && isAllocationValid()) ? Rectangle alloc = ((a != null) && isAllocationValid()) ?
getInsideAllocation(a) : null; getInsideAllocation(a) : null;
int pos = changes.getOffset(); int pos = changes.getOffset();
View v = getViewAtPosition(pos, alloc); View v = getViewAtPosition(pos, alloc);
if (v != null) if (v != null)
@ -669,7 +687,7 @@ return p + 1;
* This is called by the <code>setParent</code> method. * This is called by the <code>setParent</code> method.
* Subclasses can re-implement this to initialize their * Subclasses can re-implement this to initialize their
* child views in a different manner. The default * child views in a different manner. The default
* implementation creates a child view for each * implementation creates a child view for each
* child element. * child element.
* *
* @param f the view factory * @param f the view factory
@ -765,8 +783,8 @@ return p + 1;
*/ */
@Override @Override
public Shape modelToView(int p0, Position.Bias b0, public Shape modelToView(int p0, Position.Bias b0,
int p1, Position.Bias b1, int p1, Position.Bias b1,
Shape a) throws BadLocationException { Shape a) throws BadLocationException {
Shape s0 = modelToView(p0, a, b0); Shape s0 = modelToView(p0, a, b0);
Shape s1; Shape s1;
@ -779,9 +797,9 @@ return p + 1;
if (s1 == null) { if (s1 == null) {
// Assume extends left to right. // Assume extends left to right.
Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a :
a.getBounds(); a.getBounds();
s1 = new Rectangle(alloc.x + alloc.width - 1, alloc.y, s1 = new Rectangle(alloc.x + alloc.width - 1, alloc.y,
1, alloc.height); 1, alloc.height);
} }
} }
else { else {
@ -789,11 +807,11 @@ return p + 1;
} }
Rectangle r0 = s0.getBounds(); Rectangle r0 = s0.getBounds();
Rectangle r1 = (s1 instanceof Rectangle) ? (Rectangle) s1 : Rectangle r1 = (s1 instanceof Rectangle) ? (Rectangle) s1 :
s1.getBounds(); s1.getBounds();
if (r0.y != r1.y) { if (r0.y != r1.y) {
// If it spans lines, force it to be the width of the view. // If it spans lines, force it to be the width of the view.
Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a :
a.getBounds(); a.getBounds();
r0.x = alloc.x; r0.x = alloc.x;
r0.width = alloc.width; r0.width = alloc.width;
} }
@ -840,7 +858,7 @@ return p + 1;
public void paint(Graphics g, Shape a) { public void paint(Graphics g, Shape a) {
Rectangle alloc = (a instanceof Rectangle) ? Rectangle alloc = (a instanceof Rectangle) ?
(Rectangle)a : a.getBounds(); (Rectangle)a : a.getBounds();
tabBase = alloc.x; tabBase = alloc.x;
Graphics2D g2d = (Graphics2D)g; Graphics2D g2d = (Graphics2D)g;
@ -904,7 +922,7 @@ return p + 1;
/** /**
* Gives notification that something was removed from the * Gives notification that something was removed from the
* document in a location that this view is responsible for. * document in a location that this view is responsible for.
* This is implemented to simply update the children. * This is implemented to simply update the children.
* *
@ -918,12 +936,12 @@ return p + 1;
updateChildren(changes, a); updateChildren(changes, a);
Rectangle alloc = ((a != null) && isAllocationValid()) ? Rectangle alloc = ((a != null) && isAllocationValid()) ?
getInsideAllocation(a) : null; getInsideAllocation(a) : null;
int pos = changes.getOffset(); int pos = changes.getOffset();
View v = getViewAtPosition(pos, alloc); View v = getViewAtPosition(pos, alloc);
if (v != null) if (v != null)
v.removeUpdate(changes, alloc, f); v.removeUpdate(changes, alloc, f);
} }
@ -972,7 +990,7 @@ return p + 1;
/** /**
* Update the child views in response to a * Update the child views in response to a
* document event. * document event.
*/ */
void updateChildren(DocumentEvent e, Shape a) { void updateChildren(DocumentEvent e, Shape a) {
@ -1044,8 +1062,8 @@ return p + 1;
// Code folding may have hidden the last line. If so, return the last // Code folding may have hidden the last line. If so, return the last
// visible offset instead of the last offset. // visible offset instead of the last offset.
if (host.isCodeFoldingEnabled() && v==getView(getViewCount()-1) && if (v != null && host.isCodeFoldingEnabled() && v == getView(getViewCount() - 1) &&
offs==v.getEndOffset()-1) { offs == v.getEndOffset() - 1) {
offs = host.getLastVisibleOffset(); offs = host.getLastVisibleOffset();
} }
@ -1068,7 +1086,7 @@ return p + 1;
* {@inheritDoc} * {@inheritDoc}
*/ */
public int yForLineContaining(Rectangle alloc, int offs) public int yForLineContaining(Rectangle alloc, int offs)
throws BadLocationException { throws BadLocationException {
if (isAllocationValid()) { if (isAllocationValid()) {
// TODO: make cached Y_AXIS offsets valid even with folding enabled // TODO: make cached Y_AXIS offsets valid even with folding enabled
// to speed this back up! // to speed this back up!
@ -1091,8 +1109,8 @@ return p + 1;
/** /**
* Simple view of a line that wraps if it doesn't * Simple view of a line that wraps if it doesn't
* fit within the horizontal space allocated. * fit within the horizontal space allocated.
* This class tries to be lightweight by carrying little * This class tries to be lightweight by carrying little
* state of it's own and sharing the state of the outer class * state of it's own and sharing the state of the outer class
* with it's siblings. * with it's siblings.
*/ */
class WrappedLine extends View { class WrappedLine extends View {
@ -1136,10 +1154,10 @@ return p + 1;
//System.err.println("... ... ... break position p==" + p); //System.err.println("... ... ... break position p==" + p);
p0 = (p == p0) ? ++p : p; // this is the fix of #4410243 p0 = (p == p0) ? ++p : p; // this is the fix of #4410243
// we check on situation when // we check on situation when
// width is too small and // width is too small and
// break position is calculated // break position is calculated
// incorrectly. // incorrectly.
//System.err.println("... ... ... new p0==" + p0); //System.err.println("... ... ... new p0==" + p0);
} }
/* /*
@ -1161,7 +1179,7 @@ System.err.println(">>> >>> calculated number of lines for this view (line " + l
* @param axis may be either X_AXIS or Y_AXIS * @param axis may be either X_AXIS or Y_AXIS
* @return the span the view would like to be rendered into. * @return the span the view would like to be rendered into.
* Typically the view is told to render into the span * Typically the view is told to render into the span
* that is returned, although there is no guarantee. * that is returned, although there is no guarantee.
* The parent may choose to resize or break the view. * The parent may choose to resize or break the view.
* @see View#getPreferredSpan * @see View#getPreferredSpan
*/ */
@ -1170,7 +1188,7 @@ System.err.println(">>> >>> calculated number of lines for this view (line " + l
switch (axis) { switch (axis) {
case View.X_AXIS: case View.X_AXIS:
float width = getWidth(); float width = getWidth();
if (width == Integer.MAX_VALUE) { if (CommonUtils.equals(width, Integer.MAX_VALUE)) {
// We have been initially set to MAX_VALUE, but we don't // We have been initially set to MAX_VALUE, but we don't
// want this as our preferred. // want this as our preferred.
return 100f; return 100f;
@ -1212,7 +1230,7 @@ System.err.println(">>> >>> calculated number of lines for this view (line " + l
*/ */
@Override @Override
public Shape modelToView(int pos, Shape a, Position.Bias b) public Shape modelToView(int pos, Shape a, Position.Bias b)
throws BadLocationException { throws BadLocationException {
//System.err.println("--- begin modelToView ---"); //System.err.println("--- begin modelToView ---");
Rectangle alloc = a.getBounds(); Rectangle alloc = a.getBounds();
@ -1222,7 +1240,7 @@ System.err.println(">>> >>> calculated number of lines for this view (line " + l
int p0 = getStartOffset(); int p0 = getStartOffset();
int p1 = getEndOffset(); int p1 = getEndOffset();
int testP = (b == Position.Bias.Forward) ? pos : int testP = (b == Position.Bias.Forward) ? pos :
Math.max(p0, pos - 1); Math.max(p0, pos - 1);
// Get the token list for this line so we don't have to keep // Get the token list for this line so we don't have to keep
// recomputing it if this logical line spans multiple physical // recomputing it if this logical line spans multiple physical
@ -1242,9 +1260,9 @@ System.err.println(">>> >>> calculated number of lines for this view (line " + l
if ((pos >= p0) && (testP<p)) {//pos < p)) { if ((pos >= p0) && (testP<p)) {//pos < p)) {
// it's in this line // it's in this line
alloc = RSyntaxUtilities.getLineWidthUpTo( alloc = RSyntaxUtilities.getLineWidthUpTo(
textArea, s, p0, pos, textArea, s, p0, pos,
WrappedSyntaxView.this, WrappedSyntaxView.this,
alloc, alloc.x); alloc, alloc.x);
//System.err.println("--- end modelToView ---"); //System.err.println("--- end modelToView ---");
return alloc; return alloc;
} }
@ -1253,9 +1271,9 @@ System.err.println(">>> >>> calculated number of lines for this view (line " + l
// Wants end. // Wants end.
if (pos > p0) { if (pos > p0) {
alloc = RSyntaxUtilities.getLineWidthUpTo( alloc = RSyntaxUtilities.getLineWidthUpTo(
textArea, s, p0, pos, textArea, s, p0, pos,
WrappedSyntaxView.this, WrappedSyntaxView.this,
alloc, alloc.x); alloc, alloc.x);
} }
//System.err.println("--- end modelToView ---"); //System.err.println("--- end modelToView ---");
return alloc; return alloc;
@ -1351,14 +1369,9 @@ System.err.println(">>> >>> calculated number of lines for this view (line " + l
// Start at alloc.x since this chunk starts // Start at alloc.x since this chunk starts
// at the beginning of a physical line. // at the beginning of a physical line.
if (tlist == null) {
p0 = (p == p0) ? p1 : p;
alloc.y += alloc.height;
continue;
}
int n = tlist.getListOffset(textArea, int n = tlist.getListOffset(textArea,
WrappedSyntaxView.this, WrappedSyntaxView.this,
alloc.x, x); alloc.x, x);
// NOTE: We needed to add the max() with // NOTE: We needed to add the max() with
// p0 as getTokenListForLine returns -1 // p0 as getTokenListForLine returns -1
@ -1384,7 +1397,7 @@ System.err.println(">>> >>> calculated number of lines for this view (line " + l
} }
private void handleDocumentEvent(DocumentEvent e, Shape a, private void handleDocumentEvent(DocumentEvent e, Shape a,
ViewFactory f) { ViewFactory f) {
int n = calculateLineCount(); int n = calculateLineCount();
if (this.nlines != n) { if (this.nlines != n) {
this.nlines = n; this.nlines = n;

Loading…
Cancel
Save