/**
   * Returns the end of the word at the given offset.
   *
   * @param textArea The text area.
   * @param offs The offset into the text area's content.
   * @return The end offset of the word.
   * @throws BadLocationException If <code>offs</code> is invalid.
   * @see #getWordStart(RSyntaxTextArea, int)
   */
  public static int getWordEnd(RSyntaxTextArea textArea, int offs) throws BadLocationException {

    Document doc = textArea.getDocument();
    int endOffs = textArea.getLineEndOffsetOfCurrentLine();
    int lineEnd = Math.min(endOffs, doc.getLength());
    if (offs == lineEnd) { // End of the line.
      return offs;
    }

    String s = doc.getText(offs, lineEnd - offs - 1);
    if (s != null && s.length() > 0) { // Should always be true
      int i = 0;
      int count = s.length();
      char ch = s.charAt(i);
      if (Character.isWhitespace(ch)) {
        while (i < count && Character.isWhitespace(s.charAt(i++))) ;
      } else if (Character.isLetterOrDigit(ch)) {
        while (i < count && Character.isLetterOrDigit(s.charAt(i++))) ;
      } else {
        i = 2;
      }
      offs += i - 1;
    }

    return offs;
  }
Exemple #2
0
  public StringBuilder appendHTMLRepresentation(
      StringBuilder sb, RSyntaxTextArea textArea, boolean fontFamily, boolean tabsToSpaces) {

    SyntaxScheme colorScheme = textArea.getSyntaxScheme();
    Style scheme = colorScheme.getStyle(getType());
    Font font = textArea.getFontForTokenType(getType()); // scheme.font;

    if (font.isBold()) sb.append("<b>");
    if (font.isItalic()) sb.append("<em>");
    if (scheme.underline || isHyperlink()) sb.append("<u>");

    sb.append("<font");
    if (fontFamily) {
      sb.append(" face=\"").append(font.getFamily()).append("\"");
    }
    sb.append(" color=\"").append(getHTMLFormatForColor(scheme.foreground)).append("\">");

    // NOTE: Don't use getLexeme().trim() because whitespace tokens will
    // be turned into NOTHING.
    appendHtmlLexeme(textArea, sb, tabsToSpaces);

    sb.append("</font>");
    if (scheme.underline || isHyperlink()) sb.append("</u>");
    if (font.isItalic()) sb.append("</em>");
    if (font.isBold()) sb.append("</b>");

    return sb;
  }
  @Override
  public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) {

    int offs = -1;

    if (!isAllocationValid()) {
      Rectangle alloc = a.getBounds();
      setSize(alloc.width, alloc.height);
    }

    // Get the child view for the line at (x,y), and ask it for the
    // specific offset.
    Rectangle alloc = getInsideAllocation(a);
    View v = getViewAtPoint((int) x, (int) y, alloc);
    if (v != null) {
      offs = v.viewToModel(x, y, alloc, bias);
    }

    // Code folding may have hidden the last line.  If so, return the last
    // visible offset instead of the last offset.
    if (host.isCodeFoldingEnabled()
        && v == getView(getViewCount() - 1)
        && offs == v.getEndOffset() - 1) {
      offs = host.getLastVisibleOffset();
    }

    return offs;
  }
 /**
  * Determines the preferred span for this view along an axis.
  *
  * @param axis may be either View.X_AXIS or View.Y_AXIS
  * @return the span the view would like to be rendered into &gt;= 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
  */
 @Override
 public float getPreferredSpan(int axis) {
   updateMetrics();
   switch (axis) {
     case View.X_AXIS:
       float span = longLineWidth + getRhsCorrection(); // fudge factor
       if (host.getEOLMarkersVisible()) {
         span += metrics.charWidth('\u00B6');
       }
       return span;
     case View.Y_AXIS:
       // 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;
       //				return getElement().getElementCount() * lineHeight;
       int visibleLineCount = getElement().getElementCount();
       if (host.isCodeFoldingEnabled()) {
         visibleLineCount -= host.getFoldManager().getHiddenLineCount();
       }
       return visibleLineCount * (float) lineHeight;
     default:
       throw new IllegalArgumentException("Invalid axis: " + axis);
   }
 }
    /**
     * Returns whether the MLC token containing <code>offs</code> appears to have a "nested" comment
     * (i.e., contains "<code>/*</code>" somewhere inside of it). This implies that it is likely a
     * "new" MLC and needs to be closed. While not foolproof, this is usually good enough of a sign.
     *
     * @param textArea
     * @param line
     * @param offs
     * @return Whether a comment appears to be nested inside this one.
     */
    private boolean appearsNested(RSyntaxTextArea textArea, int line, int offs) {

      final int firstLine = line; // Remember the line we start at.

      while (line < textArea.getLineCount()) {
        Token t = textArea.getTokenListForLine(line);
        int i = 0;
        // If examining the first line, start at offs.
        if (line++ == firstLine) {
          t = RSyntaxUtilities.getTokenAtOffset(t, offs);
          if (t == null) { // offs was at end of the line
            continue;
          }
          i = t.documentToToken(offs);
        } else {
          i = t.getTextOffset();
        }
        int textOffset = t.getTextOffset();
        while (i < textOffset + t.length() - 1) {
          if (t.charAt(i - textOffset) == '/' && t.charAt(i - textOffset + 1) == '*') {
            return true;
          }
          i++;
        }
        // If tokens come after this one on this line, our MLC ended.
        if (t.getNextToken() != null) {
          return false;
        }
      }

      return true; // No match - MLC goes to the end of the file
    }
  /**
   * Provides a mapping from the view coordinate space to the logical coordinate space of the model.
   *
   * @param fx the X coordinate &gt;= 0
   * @param fy the Y coordinate &gt;= 0
   * @param a the allocated region to render into
   * @return the location within the model that best represents the given point in the view &gt;= 0
   */
  @Override
  public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) {

    bias[0] = Position.Bias.Forward;

    Rectangle alloc = a.getBounds();
    RSyntaxDocument doc = (RSyntaxDocument) getDocument();
    int x = (int) fx;
    int y = (int) fy;

    // If they're asking about a view position above the area covered by
    // this view, then the position is assumed to be the starting position
    // of this view.
    if (y < alloc.y) {
      return getStartOffset();
    }

    // If they're asking about a position below this view, the position
    // is assumed to be the ending position of this view.
    else if (y > alloc.y + alloc.height) {
      return host.getLastVisibleOffset();
    }

    // They're asking about a position within the coverage of this view
    // vertically.  So, we figure out which line the point corresponds to.
    // If the line is greater than the number of lines contained, then
    // simply use the last line as it represents the last possible place
    // we can position to.
    else {

      Element map = doc.getDefaultRootElement();
      int lineIndex = Math.abs((y - alloc.y) / lineHeight); // metrics.getHeight() );
      FoldManager fm = host.getFoldManager();
      // System.out.print("--- " + lineIndex);
      lineIndex += fm.getHiddenLineCountAbove(lineIndex, true);
      // System.out.println(" => " + lineIndex);
      if (lineIndex >= map.getElementCount()) {
        return host.getLastVisibleOffset();
      }

      Element line = map.getElement(lineIndex);

      // If the point is to the left of the line...
      if (x < alloc.x) {
        return line.getStartOffset();
      } else if (x > alloc.x + alloc.width) {
        return line.getEndOffset() - 1;
      } else {
        // Determine the offset into the text
        int p0 = line.getStartOffset();
        Token tokenList = doc.getTokenListForLine(lineIndex);
        tabBase = alloc.x;
        int offs = tokenList.getListOffset((RSyntaxTextArea) getContainer(), this, tabBase, x);
        return offs != -1 ? offs : p0;
      }
    } // End of else.
  }
    /**
     * Provides a mapping from the document model coordinate space to the coordinate space of the
     * view mapped to it.
     *
     * @param pos the position to convert
     * @param a the allocated region to render into
     * @return the bounding box of the given position is returned
     * @exception BadLocationException if the given position does not represent a valid location in
     *     the associated document.
     */
    @Override
    public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException {

      // System.err.println("--- begin modelToView ---");
      Rectangle alloc = a.getBounds();
      RSyntaxTextArea textArea = (RSyntaxTextArea) getContainer();
      alloc.height = textArea.getLineHeight(); // metrics.getHeight();
      alloc.width = 1;
      int p0 = getStartOffset();
      int p1 = getEndOffset();
      int testP = (b == Position.Bias.Forward) ? pos : Math.max(p0, pos - 1);

      // Get the token list for this line so we don't have to keep
      // recomputing it if this logical line spans multiple physical
      // lines.
      RSyntaxDocument doc = (RSyntaxDocument) getDocument();
      Element map = doc.getDefaultRootElement();
      int line = map.getElementIndex(p0);
      Token tokenList = doc.getTokenListForLine(line);
      float x0 = alloc.x; // 0;

      while (p0 < p1) {
        TokenSubList subList =
            TokenUtils.getSubTokenList(
                tokenList, p0, WrappedSyntaxView.this, textArea, x0, lineCountTempToken);
        x0 = subList != null ? subList.x : x0;
        tokenList = subList != null ? subList.tokenList : null;
        int p = calculateBreakPosition(p0, tokenList, x0);
        if ((pos >= p0) && (testP < p)) { // pos < p)) {
          // it's in this line
          alloc =
              RSyntaxUtilities.getLineWidthUpTo(
                  textArea, s, p0, pos, WrappedSyntaxView.this, alloc, alloc.x);
          // System.err.println("--- end modelToView ---");
          return alloc;
        }
        // if (p == p1 && pos == p1) {
        if (p == p1 - 1 && pos == p1 - 1) {
          // Wants end.
          if (pos > p0) {
            alloc =
                RSyntaxUtilities.getLineWidthUpTo(
                    textArea, s, p0, pos, WrappedSyntaxView.this, alloc, alloc.x);
          }
          // System.err.println("--- end modelToView ---");
          return alloc;
        }

        p0 = (p == p0) ? p1 : p;
        // System.err.println("... ... Incrementing y");
        alloc.y += alloc.height;
      }

      throw new BadLocationException(null, pos);
    }
 /**
  * Returns the template that should be inserted at the current caret position, assuming the
  * trigger character was pressed.
  *
  * @param textArea The text area that's getting text inserted into it.
  * @return A template that should be inserted, if appropriate, or <code>null</code> if no template
  *     should be inserted.
  */
 public CodeTemplate getTemplate(RSyntaxTextArea textArea) {
   int caretPos = textArea.getCaretPosition();
   int charsToGet = Math.min(caretPos, maxTemplateIDLength);
   try {
     Document doc = textArea.getDocument();
     doc.getText(caretPos - charsToGet, charsToGet, s);
     int index = Collections.binarySearch(templates, s, comparator);
     return index >= 0 ? (CodeTemplate) templates.get(index) : null;
   } catch (BadLocationException ble) {
     ble.printStackTrace();
     throw new InternalError("Error in CodeTemplateManager");
   }
 }
 public static void setFont(RSyntaxTextArea textArea, Font font) {
   if (font != null) {
     SyntaxScheme ss = textArea.getSyntaxScheme();
     ss = (SyntaxScheme) ss.clone();
     for (int i = 0; i < ss.getStyleCount(); i++) {
       if (ss.getStyle(i) != null) {
         ss.getStyle(i).font = font;
       }
     }
     textArea.setSyntaxScheme(ss);
     textArea.setFont(font);
   }
 }
  /**
   * Determines the position in the model that is closest to the given view location in the row
   * below. The component given must have a size to compute the result. If the component doesn't
   * have a size a value of -1 will be returned.
   *
   * @param c the editor
   * @param offs the offset in the document >= 0
   * @param x the X coordinate >= 0
   * @return the position >= 0 if the request can be computed, otherwise a value of -1 will be
   *     returned.
   * @exception BadLocationException if the offset is out of range
   */
  public static final int getPositionBelow(RSyntaxTextArea c, int offs, float x, TabExpander e)
      throws BadLocationException {

    TokenOrientedView tov = (TokenOrientedView) e;
    Token token = tov.getTokenListForPhysicalLineBelow(offs);
    if (token == null) return -1;

    // A line containing only Token.NULL is an empty line.
    else if (token.type == Token.NULL) {
      int line = c.getLineOfOffset(offs); // Sure to be > c.getLineCount()-1 ??
      return c.getLineStartOffset(line + 1);
    } else {
      return token.getListOffset(c, e, 0, x);
    }
  }
  /**
   * Provides a way to determine the next visually represented model location at which 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.
   *
   * <p>NOTE: You should only call this method if the passed-in <code>javax.swing.text.View</code>
   * is an instance of {@link TokenOrientedView} and <code>javax.swing.text.TabExpander</code>;
   * otherwise, a <code>ClassCastException</code> could be thrown.
   *
   * @param pos the position to convert >= 0
   * @param a the allocated region in which to render
   * @param direction the direction from the current position that can be thought of as the arrow
   *     keys typically found on a keyboard. This will be one of the following values:
   *     <ul>
   *       <li>SwingConstants.WEST
   *       <li>SwingConstants.EAST
   *       <li>SwingConstants.NORTH
   *       <li>SwingConstants.SOUTH
   *     </ul>
   *
   * @return the location within the model that best represents the next location visual position
   * @exception BadLocationException
   * @exception IllegalArgumentException if <code>direction</code> doesn't have one of the legal
   *     values above
   */
  public static int getNextVisualPositionFrom(
      int pos, Position.Bias b, Shape a, int direction, Position.Bias[] biasRet, View view)
      throws BadLocationException {

    biasRet[0] = Position.Bias.Forward;

    // Do we want the "next position" above, below, to the left or right?
    switch (direction) {
      case NORTH:
      case SOUTH:
        if (pos == -1) {
          pos = (direction == NORTH) ? Math.max(0, view.getEndOffset() - 1) : view.getStartOffset();
          break;
        }
        RSyntaxTextArea target = (RSyntaxTextArea) view.getContainer();
        Caret c = (target != null) ? target.getCaret() : null;
        // YECK! Ideally, the x location from the magic caret
        // position would be passed in.
        Point mcp;
        if (c != null) mcp = c.getMagicCaretPosition();
        else mcp = null;
        int x;
        if (mcp == null) {
          Rectangle loc = target.modelToView(pos);
          x = (loc == null) ? 0 : loc.x;
        } else {
          x = mcp.x;
        }
        if (direction == NORTH) pos = getPositionAbove(target, pos, x, (TabExpander) view);
        else pos = getPositionBelow(target, pos, x, (TabExpander) view);
        break;

      case WEST:
        if (pos == -1) pos = Math.max(0, view.getEndOffset() - 1);
        else pos = Math.max(0, pos - 1);
        break;

      case EAST:
        if (pos == -1) pos = view.getStartOffset();
        else pos = Math.min(pos + 1, view.getDocument().getLength());
        break;

      default:
        throw new IllegalArgumentException("Bad direction: " + direction);
    }

    return pos;
  }
Exemple #12
0
 public float getWidthUpTo(int numChars, RSyntaxTextArea textArea, TabExpander e, float x0) {
   float width = x0;
   FontMetrics fm = textArea.getFontMetricsForTokenType(getType());
   if (fm != null) {
     int w;
     int currentStart = textOffset;
     int endBefore = textOffset + numChars;
     for (int i = currentStart; i < endBefore; i++) {
       if (text[i] == '\t') {
         // Since TokenMaker implementations usually group all
         // adjacent whitespace into a single token, there
         // aren't usually any characters to compute a width
         // for here, so we check before calling.
         w = i - currentStart;
         if (w > 0) width += fm.charsWidth(text, currentStart, w);
         currentStart = i + 1;
         width = e.nextTabStop(width, 0);
       }
     }
     // Most (non-whitespace) tokens will have characters at this
     // point to get the widths for, so we don't check for w>0 (mini-
     // optimization).
     w = endBefore - currentStart;
     width += fm.charsWidth(text, currentStart, w);
   }
   return width - x0;
 }
  /**
   * Returns the start of the word at the given offset.
   *
   * @param textArea The text area.
   * @param offs The offset into the text area's content.
   * @return The start offset of the word.
   * @throws BadLocationException If <code>offs</code> is invalid.
   * @see #getWordEnd(RSyntaxTextArea, int)
   */
  public static int getWordStart(RSyntaxTextArea textArea, int offs) throws BadLocationException {

    Document doc = textArea.getDocument();
    Element line = getLineElem(doc, offs);
    if (line == null) {
      throw new BadLocationException("No word at " + offs, offs);
    }

    int lineStart = line.getStartOffset();
    if (offs == lineStart) { // Start of the line.
      return offs;
    }

    int endOffs = Math.min(offs + 1, doc.getLength());
    String s = doc.getText(lineStart, endOffs - lineStart);
    if (s != null && s.length() > 0) {
      int i = s.length() - 1;
      char ch = s.charAt(i);
      if (Character.isWhitespace(ch)) {
        while (i > 0 && Character.isWhitespace(s.charAt(i - 1))) {
          i--;
        }
        offs = lineStart + i;
      } else if (Character.isLetterOrDigit(ch)) {
        while (i > 0 && Character.isLetterOrDigit(s.charAt(i - 1))) {
          i--;
        }
        offs = lineStart + i;
      }
    }

    return offs;
  }
 /**
  * Workaround for JTextComponents allowing the caret to be rendered entirely off-screen if the
  * entire "previous" character fit entirely.
  *
  * @return The amount of space to add to the x-axis preferred span.
  */
 private int getRhsCorrection() {
   int rhsCorrection = 10;
   if (host != null) {
     rhsCorrection = host.getRightHandSideCorrection();
   }
   return rhsCorrection;
 }
Exemple #15
0
  /** 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);
  }
  /**
   * Returns the bounding box (in the current view) of a specified position in the model. This
   * method is designed for line-wrapped views to use, as it allows you to specify a "starting
   * position" in the line, from which the x-value is assumed to be zero. The idea is that you
   * specify the first character in a physical line as <code>p0</code>, as this is the character
   * where the x-pixel value is 0.
   *
   * @param textArea The text area containing the text.
   * @param s A segment in which to load the line. This is passed in so we don't have to reallocate
   *     a new <code>Segment</code> for each call.
   * @param p0 The starting position in the physical line in the document.
   * @param p1 The position for which to get the bounding box in the view.
   * @param e How to expand tabs.
   * @param rect The rectangle whose x- and width-values are changed to represent the bounding box
   *     of <code>p1</code>. This is reused to keep from needlessly reallocating Rectangles.
   * @param x0 The x-coordinate (pixel) marking the left-hand border of the text. This is useful if
   *     the text area has a border, for example.
   * @return The bounding box in the view of the character <code>p1</code>.
   * @throws BadLocationException If <code>p0</code> or <code>p1</code> is not a valid location in
   *     the specified text area's document.
   * @throws IllegalArgumentException If <code>p0</code> and <code>p1</code> are not on the same
   *     line.
   */
  public static Rectangle getLineWidthUpTo(
      RSyntaxTextArea textArea, Segment s, int p0, int p1, TabExpander e, Rectangle rect, int x0)
      throws BadLocationException {

    RSyntaxDocument doc = (RSyntaxDocument) textArea.getDocument();

    // Ensure p0 and p1 are valid document positions.
    if (p0 < 0) throw new BadLocationException("Invalid document position", p0);
    else if (p1 > doc.getLength()) throw new BadLocationException("Invalid document position", p1);

    // Ensure p0 and p1 are in the same line, and get the start/end
    // offsets for that line.
    Element map = doc.getDefaultRootElement();
    int lineNum = map.getElementIndex(p0);
    // We do ">1" because p1 might be the first position on the next line
    // or the last position on the previous one.
    // if (lineNum!=map.getElementIndex(p1))
    if (Math.abs(lineNum - map.getElementIndex(p1)) > 1)
      throw new IllegalArgumentException(
          "p0 and p1 are not on the " + "same line (" + p0 + ", " + p1 + ").");

    // Get the token list.
    Token t = doc.getTokenListForLine(lineNum);

    // Modify the token list 't' to begin at p0 (but still have correct
    // token types, etc.), and get the x-location (in pixels) of the
    // beginning of this new token list.
    makeTokenListStartAt(t, p0, e, textArea, 0);

    rect = t.listOffsetToView(textArea, e, p1, x0, rect);
    return rect;
  }
    @Override
    public LinkGeneratorResult isLinkAtOffset(RSyntaxTextArea textArea, final int offs) {
      Token token = textArea.modelToToken(offs);
      if (token == null) {
        return null;
      }

      String reference = pdeKeywords.getReference(token.getLexeme());

      if (reference != null
          || (token.getType() == TokenTypes.DATA_TYPE
              || token.getType() == TokenTypes.VARIABLE
              || token.getType() == TokenTypes.FUNCTION)) {

        return new LinkGeneratorResult() {

          @Override
          public int getSourceOffset() {
            return offs;
          }

          @Override
          public HyperlinkEvent execute() {

            LOG.fine("Open Reference: " + reference);

            Base.showReference("Reference/" + reference);

            return null;
          }
        };
      }

      return null;
    }
  /**
   * 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);
        }
      }
    }
  }
Exemple #19
0
 /** {@inheritDoc} */
 public int yForLineContaining(Rectangle alloc, int offs) throws BadLocationException {
   if (isAllocationValid()) {
     // TODO: make cached Y_AXIS offsets valid even with folding enabled
     // to speed this back up!
     Rectangle r = (Rectangle) modelToView(offs, alloc, Bias.Forward);
     if (r != null) {
       if (host.isCodeFoldingEnabled()) {
         int line = host.getLineOfOffset(offs);
         FoldManager fm = host.getFoldManager();
         if (fm.isLineHidden(line)) {
           return -1;
         }
       }
       return r.y;
     }
   }
   return -1;
 }
  /** {@inheritDoc} */
  public int yForLine(Rectangle alloc, int line) throws BadLocationException {

    // Rectangle lineArea = lineToRect(alloc, lineIndex);
    updateMetrics();
    if (metrics != null) {
      // 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;
      }
    }

    return -1;
  }
 /**
  * Determine the rectangle that represents the given line.
  *
  * @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.
  */
 protected Rectangle lineToRect(Shape a, int line) {
   Rectangle r = null;
   updateMetrics();
   if (metrics != null) {
     Rectangle alloc = a.getBounds();
     // 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 != 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;
 }
 /** Checks to see if the font metrics and longest line are up-to-date. */
 private void updateMetrics() {
   host = (RSyntaxTextArea) getContainer();
   Font f = host.getFont();
   if (font != f) {
     // The font changed, we need to recalculate the longest line!
     // This also updates cached font and tab size.
     calculateLongestLine();
   }
 }
  private void changeStyleProgrammatically() {

    // Set the font for all token types.
    setFont(textArea, new Font("Courier New", Font.PLAIN, 12));

    // Change a few things here and there.
    SyntaxScheme scheme = textArea.getSyntaxScheme();
    scheme.getStyle(Token.RESERVED_WORD).background = Color.white;
    scheme.getStyle(Token.RESERVED_WORD).foreground = Color.MAGENTA.darker().darker();

    scheme.getStyle(Token.DATA_TYPE).foreground = Color.blue;
    scheme.getStyle(Token.LITERAL_STRING_DOUBLE_QUOTE).underline = true;
    scheme.getStyle(Token.LITERAL_NUMBER_HEXADECIMAL).underline = true;
    scheme.getStyle(Token.LITERAL_NUMBER_HEXADECIMAL).background = Color.pink;

    scheme.getStyle(Token.COMMENT_EOL).font = new Font("Georgia", Font.ITALIC, 10);

    textArea.revalidate();
  }
    private void insertBreakInMLC(ActionEvent e, RSyntaxTextArea textArea, int line) {

      Matcher m = null;
      int start = -1;
      int end = -1;
      try {
        start = textArea.getLineStartOffset(line);
        end = textArea.getLineEndOffset(line);
        String text = textArea.getText(start, end - start);
        m = p.matcher(text);
      } catch (BadLocationException ble) { // Never happens
        UIManager.getLookAndFeel().provideErrorFeedback(textArea);
        ble.printStackTrace();
        return;
      }

      if (m.lookingAt()) {

        String leadingWS = m.group(1);
        String mlcMarker = m.group(2);

        // If the caret is "inside" any leading whitespace or MLC
        // marker, move it to the end of the line.
        int dot = textArea.getCaretPosition();
        if (dot >= start && dot < start + leadingWS.length() + mlcMarker.length()) {
          // If we're in the whitespace before the very start of the
          // MLC though, just insert a normal newline
          if (mlcMarker.charAt(0) == '/') {
            handleInsertBreak(textArea, true);
            return;
          }
          textArea.setCaretPosition(end - 1);
        }

        boolean firstMlcLine = mlcMarker.charAt(0) == '/';
        boolean nested = appearsNested(textArea, line, start + leadingWS.length() + 2);
        String header = leadingWS + (firstMlcLine ? " * " : "*") + m.group(3);
        textArea.replaceSelection("\n" + header);
        if (nested) {
          dot = textArea.getCaretPosition(); // Has changed
          textArea.insert("\n" + leadingWS + " */", dot);
          textArea.setCaretPosition(dot);
        }

      } else {
        handleInsertBreak(textArea, true);
      }
    }
Exemple #25
0
  /**
   * Sets the allocation rectangle for a given line's view, but sets the y value to the passed-in
   * value. This should be used instead of {@link #childAllocation(int, Rectangle)} since it allows
   * you to account for hidden lines in collapsed fold regions.
   *
   * @param line
   * @param y
   * @param alloc
   */
  private void childAllocation2(int line, int y, Rectangle alloc) {
    alloc.x += getOffset(X_AXIS, line);
    alloc.y += y;
    alloc.width = getSpan(X_AXIS, line);
    alloc.height = getSpan(Y_AXIS, line);

    // FIXME: This is required due to a bug that I can't track down.  The
    // top margin is being added twice somewhere in wrapped views, so we
    // have to adjust for it here.
    alloc.y -= host.getMargin().top;
  }
Exemple #26
0
 private void handleDocumentEvent(DocumentEvent e, Shape a, ViewFactory f) {
   int n = calculateLineCount();
   if (this.nlines != n) {
     this.nlines = n;
     WrappedSyntaxView.this.preferenceChanged(this, false, true);
     // have to repaint any views after the receiver.
     RSyntaxTextArea textArea = (RSyntaxTextArea) getContainer();
     textArea.repaint();
     // Must also revalidate container so gutter components, such
     // as line numbers, get updated for this line's new height
     Gutter gutter = RSyntaxUtilities.getGutter(textArea);
     if (gutter != null) {
       gutter.revalidate();
       gutter.repaint();
     }
   } else if (a != null) {
     Component c = getContainer();
     Rectangle alloc = (Rectangle) a;
     c.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
   }
 }
Exemple #27
0
  /**
   * Appends an HTML version of the lexeme of this token (i.e. no style HTML, but replacing chars
   * such as <code>\t</code>, <code>&lt;</code> and <code>&gt;</code> with their escapes).
   *
   * @param textArea The text area.
   * @param sb The buffer to append to.
   * @param tabsToSpaces Whether to convert tabs into spaces.
   * @return The same buffer.
   */
  private final StringBuilder appendHtmlLexeme(
      RSyntaxTextArea textArea, StringBuilder sb, boolean tabsToSpaces) {

    boolean lastWasSpace = false;
    int i = textOffset;
    int lastI = i;
    String tabStr = null;

    while (i < textOffset + textCount) {
      char ch = text[i];
      switch (ch) {
        case ' ':
          sb.append(text, lastI, i - lastI);
          lastI = i + 1;
          sb.append(lastWasSpace ? "&nbsp;" : " ");
          lastWasSpace = true;
          break;
        case '\t':
          sb.append(text, lastI, i - lastI);
          lastI = i + 1;
          if (tabsToSpaces && tabStr == null) {
            tabStr = "";
            for (int j = 0; j < textArea.getTabSize(); j++) {
              tabStr += "&nbsp;";
            }
          }
          sb.append(tabsToSpaces ? tabStr : "&#09;");
          lastWasSpace = false;
          break;
        case '<':
          sb.append(text, lastI, i - lastI);
          lastI = i + 1;
          sb.append("&lt;");
          lastWasSpace = false;
          break;
        case '>':
          sb.append(text, lastI, i - lastI);
          lastI = i + 1;
          sb.append("&gt;");
          lastWasSpace = false;
          break;
        default:
          lastWasSpace = false;
          break;
      }
      i++;
    }
    if (lastI < textOffset + textCount) {
      sb.append(text, lastI, textOffset + textCount - lastI);
    }
    return sb;
  }
  /**
   * Draws the passed-in text using syntax highlighting for the current language. It is assumed that
   * the entire line is either not in a selected region, or painting with a selection-foreground
   * color is turned 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.
   * @return The x-coordinate representing the end of the painted text.
   */
  private float drawLine(
      TokenPainter painter, Token token, Graphics2D g, float x, float y, int line) {

    float nextX = x; // The x-value at the end of our text.
    boolean paintBG = host.getPaintTokenBackgrounds(line, y);

    while (token != null && token.isPaintable() && nextX < clipEnd) {
      nextX = painter.paint(token, g, nextX, y, host, this, clipStart, paintBG);
      token = token.getNextToken();
    }

    // NOTE: We should re-use code from Token (paintBackground()) here,
    // but don't because I'm just too lazy.
    if (host.getEOLMarkersVisible()) {
      g.setColor(host.getForegroundForTokenType(Token.WHITESPACE));
      g.setFont(host.getFontForTokenType(Token.WHITESPACE));
      g.drawString("\u00B6", nextX, y);
    }

    // Return the x-coordinate at the end of the painted text.
    return nextX;
  }
 /**
  * Returns a token list for the <i>physical</i> line below the physical line containing the
  * specified offset into the document. Note that for this plain (non-wrapped) view, this is simply
  * the token list for the logical line below the line containing <code>offset</code>, since lines
  * are not wrapped.
  *
  * @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.
  */
 public Token getTokenListForPhysicalLineBelow(int offset) {
   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);
   //		int lineCount = map.getElementCount();
   //		if (line<lineCount-1)
   //			return document.getTokenListForLine(line+1);
   return null;
 }
  /**
   * 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);
        }
      }
    }
  }