|
|
@ -9,24 +9,37 @@ |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
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}. |
|
|
|
* |
|
|
|
* |
|
|
@ -149,8 +162,7 @@ public class SyntaxView extends View implements TabExpander, |
|
|
|
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(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -233,8 +245,7 @@ public class SyntaxView extends View implements TabExpander, |
|
|
|
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, |
|
|
@ -320,8 +331,8 @@ public class SyntaxView extends View implements TabExpander, |
|
|
|
* 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, |
|
|
@ -341,7 +352,7 @@ public class SyntaxView extends View implements TabExpander, |
|
|
|
* 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) { |
|
|
@ -420,8 +431,7 @@ if (fm==null) { |
|
|
|
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); |
|
|
@ -455,8 +465,7 @@ 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) { |
|
|
@ -501,7 +510,7 @@ else { |
|
|
|
// 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; |
|
|
@ -520,7 +529,7 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
* @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 |
|
|
|
*/ |
|
|
|
*/ |
|
|
@ -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 |
|
|
@ -578,9 +587,9 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
* @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 |
|
|
@ -605,8 +614,7 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
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(); |
|
|
@ -720,8 +728,7 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
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); |
|
|
|
} |
|
|
|
} |
|
|
@ -846,9 +853,7 @@ if (host.isCodeFoldingEnabled()) { |
|
|
|
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,14 +866,12 @@ 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!
|
|
|
@ -982,12 +985,14 @@ lineIndex += fm.getHiddenLineCountAbove(lineIndex, true); |
|
|
|
// 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 != null) { |
|
|
|
FoldManager fm = host.getFoldManager(); |
|
|
|
FoldManager fm = host.getFoldManager(); |
|
|
|
if (!fm.isLineHidden(line)) { |
|
|
|
if (!fm.isLineHidden(line)) { |
|
|
|
line -= fm.getHiddenLineCountAbove(line); |
|
|
|
line -= fm.getHiddenLineCountAbove(line); |
|
|
|
return alloc.y + line * lineHeight; |
|
|
|
return alloc.y + line * lineHeight; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
|
|
|
|
|
|
|
|