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