/** * Paints the word-wrapped text. * * @param g The graphics context in which to paint. * @param a The shape (usually a rectangle) in which to paint. */ public void paint(Graphics g, Shape a) { Rectangle alloc = (a instanceof Rectangle) ? (Rectangle) a : a.getBounds(); tabBase = alloc.x; Graphics2D g2d = (Graphics2D) g; host = (RSyntaxTextArea) getContainer(); int ascent = host.getMaxAscent(); int fontHeight = host.getLineHeight(); FoldManager fm = host.getFoldManager(); TokenPainter painter = host.getTokenPainter(); Element root = getElement(); // Whether token styles should always be painted, even in selections int selStart = host.getSelectionStart(); int selEnd = host.getSelectionEnd(); boolean useSelectedTextColor = host.getUseSelectedTextColor(); int n = getViewCount(); // Number of lines. int x = alloc.x + getLeftInset(); tempRect.y = alloc.y + getTopInset(); Rectangle clip = g.getClipBounds(); for (int i = 0; i < n; i++) { tempRect.x = x + getOffset(X_AXIS, i); // tempRect.y = y + getOffset(Y_AXIS, i); tempRect.width = getSpan(X_AXIS, i); tempRect.height = getSpan(Y_AXIS, i); // System.err.println("For line " + i + ": tempRect==" + tempRect); if (tempRect.intersects(clip)) { Element lineElement = root.getElement(i); int startOffset = lineElement.getStartOffset(); int endOffset = lineElement.getEndOffset() - 1; // Why always "-1"? View view = getView(i); if (!useSelectedTextColor || selStart == selEnd || (startOffset >= selEnd || endOffset < selStart)) { drawView(painter, g2d, alloc, view, fontHeight, tempRect.y + ascent); } else { // System.out.println("Drawing line with selection: " + i); drawViewWithSelection( painter, g2d, alloc, view, fontHeight, tempRect.y + ascent, selStart, selEnd); } } tempRect.y += tempRect.height; Fold possibleFold = fm.getFoldForLine(i); if (possibleFold != null && possibleFold.isCollapsed()) { i += possibleFold.getCollapsedLineCount(); // Visible indicator of collapsed lines Color c = RSyntaxUtilities.getFoldedLineBottomColor(host); if (c != null) { g.setColor(c); g.drawLine(x, tempRect.y - 1, alloc.width, tempRect.y - 1); } } } }
/** Overridden to allow for folded regions. */ @Override protected View getViewAtPoint(int x, int y, Rectangle alloc) { int lineCount = getViewCount(); int curY = alloc.y + getOffset(Y_AXIS, 0); // Always at least 1 line host = (RSyntaxTextArea) getContainer(); FoldManager fm = host.getFoldManager(); for (int line = 1; line < lineCount; line++) { int span = getSpan(Y_AXIS, line - 1); if (y < curY + span) { childAllocation2(line - 1, curY, alloc); return getView(line - 1); } curY += span; Fold fold = fm.getFoldForLine(line - 1); if (fold != null && fold.isCollapsed()) { line += fold.getCollapsedLineCount(); } } // Not found - return last line's view. childAllocation2(lineCount - 1, curY, alloc); return getView(lineCount - 1); }
private Fold findOpenFoldClosestTo(Point p) { Fold fold = null; RSyntaxTextArea rsta = (RSyntaxTextArea) textArea; if (rsta.isCodeFoldingEnabled()) { // Should always be true int offs = rsta.viewToModel(p); // TODO: Optimize me if (offs > -1) { try { int line = rsta.getLineOfOffset(offs); int origLine = line; FoldManager fm = rsta.getFoldManager(); do { fold = fm.getFoldForLine(line); } while (fold == null && line-- >= 0); if (fold != null && !fold.containsOrStartsOnLine(origLine)) { // Found closest fold, but doesn't actually contain line fold = null; } } catch (BadLocationException ble) { ble.printStackTrace(); // Never happens } } } return fold; }
/** * Creates a fold that is a child of this one. * * @param type The type of fold. * @param startOffs The starting offset of the fold. * @return The child fold. * @throws BadLocationException If <code>startOffs</code> is invalid. * @see FoldType */ public Fold createChild(int type, int startOffs) throws BadLocationException { Fold child = new Fold(type, textArea, startOffs); child.parent = this; if (children == null) { children = new ArrayList<Fold>(); } children.add(child); return child; }
/** * Returns the "deepest" fold containing the specified offset. It is assumed that it's already * been verified that <code>offs</code> is indeed contained in this fold. * * @param offs The offset. * @return The fold, or <code>null</code> if no child fold also contains the offset. * @see FoldManager#getDeepestFoldContaining(int) */ Fold getDeepestFoldContaining(int offs) { Fold deepestFold = this; for (int i = 0; i < getChildCount(); i++) { Fold fold = getChild(i); if (fold.containsOffset(offs)) { deepestFold = fold.getDeepestFoldContaining(offs); break; } } return deepestFold; }
/** * Removes this fold from its parent. This should only be called by {@link FoldParser} * implementations if they determine that a fold is all on a single line (and thus shouldn't be * remembered) after creating it. * * @return Whether this fold had a parent to be removed from. * @see #isOnSingleLine() */ public boolean removeFromParent() { if (parent != null) { parent.removeMostRecentChild(); parent = null; return true; } return false; }
private void updateChildCollapsedLineCount(int count) { childCollapsedLineCount += count; // if (childCollapsedLineCount>getLineCount()) { // Thread.dumpStack(); // } if (!collapsed && parent != null) { parent.updateChildCollapsedLineCount(count); } }
/** * Overridden to show the content of a collapsed fold on mouse-overs. * * @param e The mouse location. */ public String getToolTipText(MouseEvent e) { String text = null; RSyntaxTextArea rsta = (RSyntaxTextArea) textArea; if (rsta.isCodeFoldingEnabled()) { FoldManager fm = rsta.getFoldManager(); int pos = rsta.viewToModel(new Point(0, e.getY())); if (pos >= 0) { // Not -1 int line = 0; try { line = rsta.getLineOfOffset(pos); } catch (BadLocationException ble) { ble.printStackTrace(); // Never happens return null; } Fold fold = fm.getFoldForLine(line); if (fold != null && fold.isCollapsed()) { int endLine = fold.getEndLine(); if (fold.getLineCount() > 25) { // Not too big endLine = fold.getStartLine() + 25; } StringBuffer sb = new StringBuffer("<html><nobr>"); while (line <= endLine && line < rsta.getLineCount()) { // Sanity Token t = rsta.getTokenListForLine(line); while (t != null && t.isPaintable()) { t.appendHTMLRepresentation(sb, rsta, true, true); t = t.getNextToken(); } sb.append("<br>"); line++; } text = sb.toString(); } } } return text; }
/** * Fetches the allocation for the given child view to render into. * * <p>Overridden to account for lines hidden by collapsed folded regions. * * @param line The index of the child, >= 0 && < getViewCount() * @param a The allocation to this view * @return The allocation to the child */ public Shape getChildAllocationImpl(int line, Shape a) { Rectangle alloc = getInsideAllocation(a); host = (RSyntaxTextArea) getContainer(); FoldManager fm = host.getFoldManager(); int y = alloc.y; // TODO: Make cached getOffset() calls for Y_AXIS valid even for // folding, to speed this up! for (int i = 0; i < line; i++) { y += getSpan(Y_AXIS, i); Fold fold = fm.getFoldForLine(i); if (fold != null && fold.isCollapsed()) { i += fold.getCollapsedLineCount(); } } childAllocation2(line, y, alloc); return alloc; }
public void mouseClicked(MouseEvent e) { // // TODO: Implement code folding with word wrap enabled // if (textArea.getLineWrap()) { // UIManager.getLookAndFeel().provideErrorFeedback(textArea); // return; // } Point p = e.getPoint(); int line = rowAtPoint(p); RSyntaxTextArea rsta = (RSyntaxTextArea) textArea; FoldManager fm = rsta.getFoldManager(); Fold fold = fm.getFoldForLine(line); if (fold != null) { fold.toggleCollapsedState(); getGutter().repaint(); textArea.repaint(); } }
/** * Paints the word-wrapped text. * * @param g The graphics context in which to paint. * @param a The shape (usually a rectangle) in which to paint. */ public void paint(Graphics g, Shape a) { Rectangle alloc = (a instanceof Rectangle) ? (Rectangle) a : a.getBounds(); tabBase = alloc.x; Graphics2D g2d = (Graphics2D) g; host = (RSyntaxTextArea) getContainer(); int ascent = host.getMaxAscent(); int fontHeight = host.getLineHeight(); FoldManager fm = host.getFoldManager(); int n = getViewCount(); // Number of lines. int x = alloc.x + getLeftInset(); tempRect.y = alloc.y + getTopInset(); Rectangle clip = g.getClipBounds(); for (int i = 0; i < n; i++) { tempRect.x = x + getOffset(X_AXIS, i); // tempRect.y = y + getOffset(Y_AXIS, i); tempRect.width = getSpan(X_AXIS, i); tempRect.height = getSpan(Y_AXIS, i); // System.err.println("For line " + i + ": tempRect==" + tempRect); if (tempRect.intersects(clip)) { View view = getView(i); drawView(g2d, alloc, view, fontHeight, tempRect.y + ascent); } tempRect.y += tempRect.height; Fold possibleFold = fm.getFoldForLine(i); if (possibleFold != null && possibleFold.isCollapsed()) { i += possibleFold.getCollapsedLineCount(); // Visible indicator of collapsed lines Color c = RSyntaxUtilities.getFoldedLineBottomColor(host); if (c != null) { g.setColor(c); g.drawLine(x, tempRect.y - 1, alloc.width, tempRect.y - 1); } } } }
/** * Sets whether this <code>Fold</code> is collapsed. Calling this method will update both the text * area and all <code>Gutter</code> components. * * @param collapsed Whether this fold should be collapsed. * @see #isCollapsed() * @see #toggleCollapsedState() */ public void setCollapsed(boolean collapsed) { if (collapsed != this.collapsed) { // Change our fold state and cached info about folded line count. int lineCount = getLineCount(); int linesToCollapse = lineCount - childCollapsedLineCount; if (!collapsed) { // If we're expanding linesToCollapse = -linesToCollapse; } // System.out.println("Hiding lines: " + linesToCollapse + // " (" + lineCount + ", " + linesToCollapse + ")"); this.collapsed = collapsed; if (parent != null) { parent.updateChildCollapsedLineCount(linesToCollapse); } // If an end point of the selection is being hidden, move the caret // "out" of the fold. if (collapsed) { int dot = textArea.getSelectionStart(); // Forgive variable name Element root = textArea.getDocument().getDefaultRootElement(); int dotLine = root.getElementIndex(dot); boolean updateCaret = containsLine(dotLine); if (!updateCaret) { int mark = textArea.getSelectionEnd(); if (mark != dot) { int markLine = root.getElementIndex(mark); updateCaret = containsLine(markLine); } } if (updateCaret) { dot = root.getElement(getStartLine()).getEndOffset() - 1; textArea.setCaretPosition(dot); } } textArea.foldToggled(this); } }
/** {@inheritDoc} */ @Override public List<Fold> getFolds(RSyntaxTextArea textArea) { List<Fold> folds = new ArrayList<Fold>(); Fold currentFold = null; int lineCount = textArea.getLineCount(); boolean inMLC = false; int mlcStart = 0; int importStartLine = -1; int lastSeenImportLine = -1; int importGroupStartOffs = -1; int importGroupEndOffs = -1; int lastRightCurlyLine = -1; Fold prevFold = null; try { for (int line = 0; line < lineCount; line++) { Token t = textArea.getTokenListForLine(line); while (t != null && t.isPaintable()) { if (getFoldableMultiLineComments() && t.isComment()) { // Java-specific stuff if (java) { if (importStartLine > -1) { if (lastSeenImportLine > importStartLine) { Fold fold = null; // Any imports found *should* be a top-level fold, // but we're extra lenient here and allow groups // of them anywhere to keep our parser better-behaved // if they have random "imports" throughout code. if (currentFold == null) { fold = new Fold(FoldType.IMPORTS, textArea, importGroupStartOffs); folds.add(fold); } else { fold = currentFold.createChild(FoldType.IMPORTS, importGroupStartOffs); } fold.setEndOffset(importGroupEndOffs); } importStartLine = lastSeenImportLine = importGroupStartOffs = importGroupEndOffs = -1; } } if (inMLC) { // If we found the end of an MLC that started // on a previous line... if (t.endsWith(C_MLC_END)) { int mlcEnd = t.getEndOffset() - 1; if (currentFold == null) { currentFold = new Fold(FoldType.COMMENT, textArea, mlcStart); currentFold.setEndOffset(mlcEnd); folds.add(currentFold); currentFold = null; } else { currentFold = currentFold.createChild(FoldType.COMMENT, mlcStart); currentFold.setEndOffset(mlcEnd); currentFold = currentFold.getParent(); } // System.out.println("Ending MLC at: " + mlcEnd + ", parent==" + currentFold); inMLC = false; mlcStart = 0; } // Otherwise, this MLC is continuing on to yet // another line. } else { // If we're an MLC that ends on a later line... if (t.getType() != Token.COMMENT_EOL && !t.endsWith(C_MLC_END)) { // System.out.println("Starting MLC at: " + t.offset); inMLC = true; mlcStart = t.getOffset(); } } } else if (isLeftCurly(t)) { // Java-specific stuff if (java) { if (importStartLine > -1) { if (lastSeenImportLine > importStartLine) { Fold fold = null; // Any imports found *should* be a top-level fold, // but we're extra lenient here and allow groups // of them anywhere to keep our parser better-behaved // if they have random "imports" throughout code. if (currentFold == null) { fold = new Fold(FoldType.IMPORTS, textArea, importGroupStartOffs); folds.add(fold); } else { fold = currentFold.createChild(FoldType.IMPORTS, importGroupStartOffs); } fold.setEndOffset(importGroupEndOffs); } importStartLine = lastSeenImportLine = importGroupStartOffs = importGroupEndOffs = -1; } } // If a new fold block starts on the same line as the // previous one ends, we treat it as one big block // (e.g. K&R-style "} else {") if (prevFold != null && line == lastRightCurlyLine) { currentFold = prevFold; // Keep currentFold.endOffset where it was, so that // unclosed folds at end of the file work as well // as possible prevFold = null; lastRightCurlyLine = -1; } else if (currentFold == null) { // A top-level fold currentFold = new Fold(FoldType.CODE, textArea, t.getOffset()); folds.add(currentFold); } else { // A nested fold currentFold = currentFold.createChild(FoldType.CODE, t.getOffset()); } } else if (isRightCurly(t)) { if (currentFold != null) { currentFold.setEndOffset(t.getOffset()); Fold parentFold = currentFold.getParent(); // System.out.println("... Adding regular fold at " + t.offset + ", parent==" + // parentFold); // Don't add fold markers for single-line blocks if (currentFold.isOnSingleLine()) { if (!currentFold.removeFromParent()) { folds.remove(folds.size() - 1); } } else { // Remember the end of the last completed fold, // in case it needs to get merged with the next // one (e.g. K&R "} else {" style) lastRightCurlyLine = line; prevFold = currentFold; } currentFold = parentFold; } } // Java-specific folding rules else if (java) { if (t.is(Token.RESERVED_WORD, KEYWORD_IMPORT)) { if (importStartLine == -1) { importStartLine = line; importGroupStartOffs = t.getOffset(); importGroupEndOffs = t.getOffset(); } lastSeenImportLine = line; } else if (importStartLine > -1 && t.isIdentifier() && // SEPARATOR && t.isSingleChar(';')) { importGroupEndOffs = t.getOffset(); } } t = t.getNextToken(); } } } catch (BadLocationException ble) { // Should never happen ble.printStackTrace(); } return folds; }
/** * Paints folding icons when line wrapping is enabled. * * @param g The graphics context. */ private void paintComponentWrapped(Graphics g) { // The variables we use are as follows: // - visibleRect is the "visible" area of the text area; e.g. // [0,100, 300,100+(lineCount*cellHeight)-1]. // actualTop.y is the topmost-pixel in the first logical line we // paint. Note that we may well not paint this part of the logical // line, as it may be broken into many physical lines, with the first // few physical lines scrolled past. Note also that this is NOT the // visible rect of this line number list; this line number list has // visible rect == [0,0, insets.left-1,visibleRect.height-1]. // - offset (<=0) is the y-coordinate at which we begin painting when // we begin painting with the first logical line. This can be // negative, signifying that we've scrolled past the actual topmost // part of this line. // The algorithm is as follows: // - Get the starting y-coordinate at which to paint. This may be // above the first visible y-coordinate as we're in line-wrapping // mode, but we always paint entire logical lines. // - Paint that line's indicator, if appropriate. Increment y to be // just below the are we just painted (i.e., the beginning of the // next logical line's view area). // - Get the ending visual position for that line. We can now loop // back, paint this line, and continue until our y-coordinate is // past the last visible y-value. // We avoid using modelToView/viewToModel where possible, as these // methods trigger a parsing of the line into syntax tokens, which is // costly. It's cheaper to just grab the child views' bounds. // Some variables we'll be using. int width = getWidth(); RTextAreaUI ui = (RTextAreaUI) textArea.getUI(); View v = ui.getRootView(textArea).getView(0); Document doc = textArea.getDocument(); Element root = doc.getDefaultRootElement(); int topPosition = textArea.viewToModel(new Point(visibleRect.x, visibleRect.y)); int topLine = root.getElementIndex(topPosition); int cellHeight = textArea.getLineHeight(); FoldManager fm = ((RSyntaxTextArea) textArea).getFoldManager(); // Compute the y at which to begin painting text, taking into account // that 1 logical line => at least 1 physical line, so it may be that // y<0. The computed y-value is the y-value of the top of the first // (possibly) partially-visible view. Rectangle visibleEditorRect = ui.getVisibleEditorRect(); Rectangle r = LineNumberList.getChildViewBounds(v, topLine, visibleEditorRect); int y = r.y; y += (cellHeight - collapsedFoldIcon.getIconHeight()) / 2; int visibleBottom = visibleRect.y + visibleRect.height; int x = width - 10; int line = topLine; boolean paintingOutlineLine = foldWithOutlineShowing != null && foldWithOutlineShowing.containsLine(line); int lineCount = root.getElementCount(); while (y < visibleBottom && line < lineCount) { int curLineH = LineNumberList.getChildViewBounds(v, line, visibleEditorRect).height; if (paintingOutlineLine) { g.setColor(getForeground()); int w2 = width / 2; if (line == foldWithOutlineShowing.getEndLine()) { int y2 = y + curLineH - cellHeight / 2; g.drawLine(w2, y, w2, y2); g.drawLine(w2, y2, width - 2, y2); paintingOutlineLine = false; } else { g.drawLine(w2, y, w2, y + curLineH); } } Fold fold = fm.getFoldForLine(line); if (fold != null) { if (fold == foldWithOutlineShowing && !fold.isCollapsed()) { g.setColor(getForeground()); int w2 = width / 2; g.drawLine(w2, y + cellHeight / 2, w2, y + curLineH); paintingOutlineLine = true; } if (fold.isCollapsed()) { collapsedFoldIcon.paintIcon(this, g, x, y); y += LineNumberList.getChildViewBounds(v, line, visibleEditorRect).height; line += fold.getLineCount() + 1; } else { expandedFoldIcon.paintIcon(this, g, x, y); y += curLineH; line++; } } else { y += curLineH; line++; } } }
protected void paintComponent(Graphics g) { if (textArea == null) { return; } visibleRect = g.getClipBounds(visibleRect); if (visibleRect == null) { // ??? visibleRect = getVisibleRect(); } // System.out.println("IconRowHeader repainting: " + visibleRect); if (visibleRect == null) { return; } Color bg = getBackground(); if (getGutter() != null) { // Should always be true bg = getGutter().getBackground(); } g.setColor(bg); g.fillRect(0, visibleRect.y, getWidth(), visibleRect.height); RSyntaxTextArea rsta = (RSyntaxTextArea) textArea; if (!rsta.isCodeFoldingEnabled()) { return; // We should be hidden in this case, but still... } if (textArea.getLineWrap()) { paintComponentWrapped(g); return; } // Get where to start painting (top of the row). // We need to be "scrolled up" up just enough for the missing part of // the first line. int cellHeight = textArea.getLineHeight(); int topLine = visibleRect.y / cellHeight; int y = topLine * cellHeight + (cellHeight - collapsedFoldIcon.getIconHeight()) / 2; textAreaInsets = textArea.getInsets(textAreaInsets); if (textAreaInsets != null) { y += textAreaInsets.top; } // Get the first and last lines to paint. FoldManager fm = rsta.getFoldManager(); topLine += fm.getHiddenLineCountAbove(topLine, true); int width = getWidth(); int x = width - 10; int line = topLine; boolean paintingOutlineLine = foldWithOutlineShowing != null && foldWithOutlineShowing.containsLine(line); while (y < visibleRect.y + visibleRect.height) { if (paintingOutlineLine) { g.setColor(getForeground()); int w2 = width / 2; if (line == foldWithOutlineShowing.getEndLine()) { int y2 = y + cellHeight / 2; g.drawLine(w2, y, w2, y2); g.drawLine(w2, y2, width - 2, y2); paintingOutlineLine = false; } else { g.drawLine(w2, y, w2, y + cellHeight); } } Fold fold = fm.getFoldForLine(line); if (fold != null) { if (fold == foldWithOutlineShowing && !fold.isCollapsed()) { g.setColor(getForeground()); int w2 = width / 2; g.drawLine(w2, y + cellHeight / 2, w2, y + cellHeight); paintingOutlineLine = true; } if (fold.isCollapsed()) { collapsedFoldIcon.paintIcon(this, g, x, y); // Skip to next line to paint, taking extra care for lines with // block ends and begins together, e.g. "} else {" do { line += fold.getLineCount(); fold = fm.getFoldForLine(line); } while (fold != null && fold.isCollapsed()); } else { expandedFoldIcon.paintIcon(this, g, x, y); } } line++; y += cellHeight; } }
/** * Actually paints the text area. Only lines that have been damaged are repainted. * * @param g The graphics context with which to paint. * @param a The allocated region in which to render. */ @Override public void paint(Graphics g, Shape a) { RSyntaxDocument document = (RSyntaxDocument) getDocument(); Rectangle alloc = a.getBounds(); tabBase = alloc.x; host = (RSyntaxTextArea) getContainer(); Rectangle clip = g.getClipBounds(); // An attempt to speed things up for files with long lines. Note that // this will actually slow things down a bit for the common case of // regular-length lines, but it doesn't make a perceivable difference. clipStart = clip.x; clipEnd = clipStart + clip.width; lineHeight = host.getLineHeight(); ascent = host.getMaxAscent(); // metrics.getAscent(); int heightAbove = clip.y - alloc.y; int linesAbove = Math.max(0, heightAbove / lineHeight); FoldManager fm = host.getFoldManager(); linesAbove += fm.getHiddenLineCountAbove(linesAbove, true); Rectangle lineArea = lineToRect(a, linesAbove); int y = lineArea.y + ascent; int x = lineArea.x; Element map = getElement(); int lineCount = map.getElementCount(); // Whether token styles should always be painted, even in selections int selStart = host.getSelectionStart(); int selEnd = host.getSelectionEnd(); RSyntaxTextAreaHighlighter h = (RSyntaxTextAreaHighlighter) host.getHighlighter(); 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) { 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"? h.paintLayeredHighlights(g2d, startOffset, endOffset, a, host, this); // Paint a line of text. token = document.getTokenListForLine(line); if (selStart == selEnd || startOffset >= selEnd || endOffset < selStart) { drawLine(painter, token, g2d, x, y, line); } else { // System.out.println("Drawing line with selection: " + line); drawLineWithSelection(painter, token, g2d, x, y, selStart, selEnd); } if (fold != null && fold.isCollapsed()) { // Visible indicator of collapsed lines Color c = RSyntaxUtilities.getFoldedLineBottomColor(host); if (c != null) { g.setColor(c); g.drawLine(x, y + lineHeight - ascent - 1, host.getWidth(), 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) { // Fold parser identified a zero-line fold region. // This is really a bug, but we'll be graceful here // and avoid an infinite loop. break; } line += hiddenLineCount; fold = fm.getFoldForLine(line); } while (fold != null && fold.isCollapsed()); } y += lineHeight; line++; // count++; } // System.out.println("SyntaxView: lines painted=" + count); }