private void updateTemplateFromEditor(PrintfTemplate template) { ArrayList params = new ArrayList(); String format = null; int text_length = editorPane.getDocument().getLength(); try { format = editorPane.getDocument().getText(0, text_length); } catch (BadLocationException ex1) { } Element section_el = editorPane.getDocument().getDefaultRootElement(); // Get number of paragraphs. int num_para = section_el.getElementCount(); for (int p_count = 0; p_count < num_para; p_count++) { Element para_el = section_el.getElement(p_count); // Enumerate the content elements int num_cont = para_el.getElementCount(); for (int c_count = 0; c_count < num_cont; c_count++) { Element content_el = para_el.getElement(c_count); AttributeSet attr = content_el.getAttributes(); // Get the name of the style applied to this content element; may be null String sn = (String) attr.getAttribute(StyleConstants.NameAttribute); // Check if style name match if (sn != null && sn.startsWith("Parameter")) { // we extract the label. JLabel l = (JLabel) StyleConstants.getComponent(attr); if (l != null) { params.add(l.getName()); } } } } template.setFormat(format); template.setTokens(params); }
/** * 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 changed. */ protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f) { Component host = getContainer(); updateMetrics(); Element elem = getElement(); 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))) { // 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); } if (removed != null) { for (int i = 0; i < removed.length; i++) { if (removed[i] == longLine) { longLineWidth = -1; // Must do this!! calculateLongestLine(); break; } } } preferenceChanged(null, true, true); host.repaint(); } // This occurs when syntax highlighting only changes on lines // (i.e. beginning a multiline comment). 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 { Element map = getElement(); int line = map.getElementIndex(changes.getOffset()); damageLineRange(line, line, a, host); if (changes.getType() == DocumentEvent.EventType.INSERT) { // check to see if the line is longer than current // longest line. Element e = map.getElement(line); if (e == longLine) { // We must recalculate longest line's width here // because it has gotten longer. longLineWidth = getLineWidth(line); preferenceChanged(null, true, false); } 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) { if (map.getElement(line) == longLine) { // removed from longest line... recalc longLineWidth = -1; // Must do this! calculateLongestLine(); preferenceChanged(null, true, false); } } } }
/* * We need to know if the caret is currently positioned on the line we * are about to paint so the line number can be highlighted. */ private boolean isCurrentLine(int rowStartOffset) { int caretPosition = component.getCaretPosition(); Element root = component.getDocument().getDefaultRootElement(); if (root.getElementIndex(rowStartOffset) == root.getElementIndex(caretPosition)) return true; else return false; }
/** * 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); } } } }
public int computeDocumentOffset(int line, int column) throws BadLocationException { if (line < 0 || column < 0) throw new BadLocationException("Negative line/col", -1); Element lineElement = editor.getDocument().getDefaultRootElement().getElement(line - 1); int beginLineOffset = lineElement.getStartOffset(); int endLineOffset = lineElement.getEndOffset(); String text = editor.getDocument().getText(beginLineOffset, endLineOffset - beginLineOffset); int parserChar = 1; int documentChar = 0; while (parserChar < column) { if (documentChar < text.length() && text.charAt(documentChar) == '\t') { parserChar += 8; documentChar += 1; } else { parserChar += 1; documentChar += 1; } } return beginLineOffset + documentChar; }
protected int getViewIndexAtPosition(int pos) { Element elem = getElement(); if (elem.isLeaf()) { return 0; } return super.getViewIndexAtPosition(pos); }
/* * Get the line number to be drawn. The empty string will be returned * when a line of text has wrapped. */ protected String getTextLineNumber(int rowStartOffset) { Element root = component.getDocument().getDefaultRootElement(); int index = root.getElementIndex(rowStartOffset); Element line = root.getElement(index); if (line.getStartOffset() == rowStartOffset) return String.valueOf(index + 1); else return ""; }
protected void loadChildren(ViewFactory f) { Element elem = getElement(); if (elem.isLeaf()) { View v = new LabelView(elem); append(v); } else { super.loadChildren(f); } }
/** * Loads all of the children to initialize the view. This is called by the <code>setParent</code> * method. Subclasses can re-implement this to initialize their child views in a different manner. * The default implementation creates a child view for each child element. * * @param f the view factory */ protected void loadChildren(ViewFactory f) { Element e = getElement(); int n = e.getElementCount(); if (n > 0) { View[] added = new View[n]; for (int i = 0; i < n; i++) added[i] = new WrappedLine(e.getElement(i)); replace(0, 0, added); } }
/** * 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); }
/** * Alerts all listeners to this document of an insertion. This is overridden so we can update our * syntax highlighting stuff. * * <p>The syntax highlighting stuff has to be here instead of in <code>insertUpdate</code> because * <code>insertUpdate</code> is not called by the undo/redo actions, but this method is. * * @param e The change. */ protected void fireInsertUpdate(DocumentEvent e) { /* * Now that the text is actually inserted into the content and * element structure, we can update our token elements and "last * tokens on lines" structure. */ Element lineMap = getDefaultRootElement(); DocumentEvent.ElementChange change = e.getChange(lineMap); Element[] added = change == null ? null : change.getChildrenAdded(); int numLines = lineMap.getElementCount(); int line = lineMap.getElementIndex(e.getOffset()); int previousLine = line - 1; int previousTokenType = (previousLine > -1 ? lastTokensOnLines.get(previousLine) : Token.NULL); // If entire lines were added... if (added != null && added.length > 0) { Element[] removed = change.getChildrenRemoved(); int numRemoved = removed != null ? removed.length : 0; int endBefore = line + added.length - numRemoved; // System.err.println("... adding lines: " + line + " - " + (endBefore-1)); // System.err.println("... ... added: " + added.length + ", removed:" + numRemoved); for (int i = line; i < endBefore; i++) { setSharedSegment(i); // Loads line i's text into s. int tokenType = tokenMaker.getLastTokenTypeOnLine(s, previousTokenType); lastTokensOnLines.add(i, tokenType); // System.err.println("--------- lastTokensOnLines.size() == " + // lastTokensOnLines.getSize()); previousTokenType = tokenType; } // End of for (int i=line; i<endBefore; i++). // Update last tokens for lines below until they stop changing. updateLastTokensBelow(endBefore, numLines, previousTokenType); } // End of if (added!=null && added.length>0). // Otherwise, text was inserted on a single line... else { // Update last tokens for lines below until they stop changing. updateLastTokensBelow(line, numLines, previousTokenType); } // End of else. // Let all listeners know about the insertion. super.fireInsertUpdate(e); }
/** * This method is called AFTER the content has been inserted into the document and the element * structure has been updated. * * <p>The syntax-highlighting updates need to be done here (as opposed to an override of <code> * postRemoveUpdate</code>) as this method is called in response to undo/redo events, whereas * <code>postRemoveUpdate</code> is not. * * <p>Now that the text is actually inserted into the content and element structure, we can update * our token elements and "last tokens on lines" structure. * * @param chng The change that occurred. * @see #removeUpdate */ protected void fireRemoveUpdate(DocumentEvent chng) { Element lineMap = getDefaultRootElement(); int numLines = lineMap.getElementCount(); DocumentEvent.ElementChange change = chng.getChange(lineMap); Element[] removed = change == null ? null : change.getChildrenRemoved(); // If entire lines were removed... if (removed != null && removed.length > 0) { int line = change.getIndex(); // First line entirely removed. int previousLine = line - 1; // Line before that. int previousTokenType = (previousLine > -1 ? lastTokensOnLines.get(previousLine) : Token.NULL); Element[] added = change.getChildrenAdded(); int numAdded = added == null ? 0 : added.length; // Remove the cached last-token values for the removed lines. int endBefore = line + removed.length - numAdded; // System.err.println("... removing lines: " + line + " - " + (endBefore-1)); // System.err.println("... added: " + numAdded + ", removed: " + removed.length); lastTokensOnLines.removeRange( line, endBefore); // Removing values for lines [line-(endBefore-1)]. // System.err.println("--------- lastTokensOnLines.size() == " + lastTokensOnLines.getSize()); // Update last tokens for lines below until they've stopped changing. updateLastTokensBelow(line, numLines, previousTokenType); } // End of if (removed!=null && removed.size()>0). // Otherwise, text was removed from just one line... else { int line = lineMap.getElementIndex(chng.getOffset()); if (line >= lastTokensOnLines.getSize()) return; // If we're editing the last line in a document... int previousLine = line - 1; int previousTokenType = (previousLine > -1 ? lastTokensOnLines.get(previousLine) : Token.NULL); // System.err.println("previousTokenType for line : " + previousLine + " is " + // previousTokenType); // Update last tokens for lines below until they've stopped changing. updateLastTokensBelow(line, numLines, previousTokenType); } // Let all of our listeners know about the removal. super.fireRemoveUpdate(chng); }
// // Implement CaretListener interface // @Override public void caretUpdate(CaretEvent e) { // Get the line the caret is positioned on int caretPosition = component.getCaretPosition(); Element root = component.getDocument().getDefaultRootElement(); int currentLine = root.getElementIndex(caretPosition); // Need to repaint so the correct line number can be highlighted if (lastLine != currentLine) { repaint(); lastLine = currentLine; } }
public void caretUpdate(CaretEvent e) { // when the cursor moves on _textView // this method will be called. Then, we // must determine what the line number is // and update the line number view Element root = textView.getDocument().getDefaultRootElement(); int line = root.getElementIndex(e.getDot()); root = root.getElement(line); int col = root.getElementIndex(e.getDot()); lineNumberView.setText(line + ":" + col); // if text is selected then enable copy and cut boolean isSelection = e.getDot() != e.getMark(); copyAction.setEnabled(isSelection); cutAction.setEnabled(isSelection); }
/** * Returns a token list for the specified segment of text representing the specified line number. * This method is basically a wrapper for <code>tokenMaker.getTokenList</code> that takes into * account the last token on the previous line to assure token accuracy. * * @param line The line number of <code>text</code> in the document, >= 0. * @return A token list representing the specified line. */ public final Token getTokenListForLine(int line) { Element map = getDefaultRootElement(); Element elem = map.getElement(line); int startOffset = elem.getStartOffset(); // int endOffset = (line==map.getElementCount()-1 ? elem.getEndOffset() - 1: // elem.getEndOffset() - 1); int endOffset = elem.getEndOffset() - 1; // Why always "-1"? try { getText(startOffset, endOffset - startOffset, s); } catch (BadLocationException ble) { ble.printStackTrace(); return null; } int initialTokenType = line == 0 ? Token.NULL : getLastTokenTypeOnLine(line - 1); return tokenMaker.getTokenList(s, initialTokenType, startOffset); }
/** * Loads all of the children to initialize the view. This is called by the {@link #setParent} * method. Subclasses can reimplement this to initialize their child views in a different manner. * The default implementation creates a child view for each child element. * * @param f the view factory * @see #setParent */ protected void loadChildren(ViewFactory f) { if (f == null) { // No factory. This most likely indicates the parent view // has changed out from under us, bail! return; } Element e = getElement(); int n = e.getElementCount(); if (n > 0) { View[] added = new View[n]; for (int i = 0; i < n; i++) { added[i] = f.create(e.getElement(i)); } replace(0, 0, added); } }
/** * Iterate over the lines represented by the child elements 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 longest line. */ void calculateLongestLine() { Component c = getContainer(); font = c.getFont(); metrics = c.getFontMetrics(font); tabSize = getTabSize() * metrics.charWidth(' '); Element lines = getElement(); int n = lines.getElementCount(); for (int i = 0; i < n; i++) { Element line = lines.getElement(i); float w = getLineWidth(i); if (w > longLineWidth) { longLineWidth = w; longLine = line; } } }
/** Calculate the number of lines that will be rendered by logical line when it is wrapped. */ final int calculateLineCount() { int nlines = 0; int startOffset = getStartOffset(); int p1 = getEndOffset(); // Get the token list for this line so we don't have to keep // recomputing it if this logical line spans multiple physical // lines. RSyntaxTextArea textArea = (RSyntaxTextArea) getContainer(); RSyntaxDocument doc = (RSyntaxDocument) getDocument(); Element map = doc.getDefaultRootElement(); int line = map.getElementIndex(startOffset); Token tokenList = doc.getTokenListForLine(line); float x0 = 0; // FIXME: should be alloc.x!! alloc.x;//0; // System.err.println(">>> calculateLineCount: " + startOffset + "-" + p1); for (int p0 = startOffset; p0 < p1; ) { // System.err.println("... ... " + p0 + ", " + p1); nlines += 1; 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); // System.err.println("... ... ... break position p==" + p); p0 = (p == p0) ? ++p : p; // this is the fix of #4410243 // we check on situation when // width is too small and // break position is calculated // incorrectly. // System.err.println("... ... ... new p0==" + p0); } /* int numLines = 0; try { numLines = textArea.getLineCount(); } catch (BadLocationException ble) { ble.printStackTrace(); } System.err.println(">>> >>> calculated number of lines for this view (line " + line + "/" + numLines + ": " + nlines); */ return nlines; }
private String addWhiteSpace(Document doc, int offset) throws BadLocationException { StringBuilder whiteSpace = new StringBuilder("\n"); Element rootElement = doc.getDefaultRootElement(); int line = rootElement.getElementIndex(offset); int i = rootElement.getElement(line).getStartOffset(); while (true) { String temp = doc.getText(i, 1); if (temp.equals(" ") || temp.equals("\t")) { whiteSpace.append(temp); i++; } else break; } return whiteSpace.toString(); }
/** * Updates internal state information; e.g. the "last tokens on lines" data. After this, a changed * update is fired to let listeners know that the document's structure has changed. * * <p>This is called internally whenever the syntax style changes. */ protected void updateSyntaxHighlightingInformation() { // Reinitialize the "last token on each line" array. Note that since // the actual text in the document isn't changing, the number of lines // is the same. Element map = getDefaultRootElement(); int numLines = map.getElementCount(); int lastTokenType = Token.NULL; for (int i = 0; i < numLines; i++) { setSharedSegment(i); lastTokenType = tokenMaker.getLastTokenTypeOnLine(s, lastTokenType); lastTokensOnLines.set(i, lastTokenType); } // Let everybody know that syntax styles have (probably) changed. fireChangedUpdate(new DefaultDocumentEvent(0, numLines - 1, DocumentEvent.EventType.CHANGE)); }
/** * Makes our private <code>Segment s</code> point to the text in our document referenced by the * specified element. Note that <code>line</code> MUST be a valid line number in the document. * * @param line The line number you want to get. */ private final void setSharedSegment(int line) { Element map = getDefaultRootElement(); // int numLines = map.getElementCount(); Element element = map.getElement(line); if (element == null) throw new InternalError("Invalid line number: " + line); int startOffset = element.getStartOffset(); // int endOffset = (line==numLines-1 ? // element.getEndOffset()-1 : element.getEndOffset() - 1); int endOffset = element.getEndOffset() - 1; // Why always "-1"? try { getText(startOffset, endOffset - startOffset, s); } catch (BadLocationException ble) { throw new InternalError("Text range not in document: " + startOffset + "-" + endOffset); } }
void editorPane_keyPressed(KeyEvent e) { StyledDocument doc = editorPane.getStyledDocument(); int pos = editorPane.getCaretPosition(); int code = e.getKeyCode(); Element el; switch (code) { case KeyEvent.VK_BACK_SPACE: case KeyEvent.VK_DELETE: case KeyEvent.VK_LEFT: case KeyEvent.VK_KP_LEFT: if (pos == 0) return; // we want to get the element to the left of position. el = doc.getCharacterElement(pos - 1); break; case KeyEvent.VK_RIGHT: case KeyEvent.VK_KP_RIGHT: // we want to get the element to the right of position. el = doc.getCharacterElement(pos + 1); break; default: return; // bail we don't handle it. } AttributeSet attr = el.getAttributes(); String el_name = (String) attr.getAttribute(StyleConstants.NameAttribute); int el_range = el.getEndOffset() - el.getStartOffset() - 1; if (el_name.startsWith("Parameter") && StyleConstants.getComponent(attr) != null) { try { switch (code) { case KeyEvent.VK_BACK_SPACE: case KeyEvent.VK_DELETE: doc.remove(el.getStartOffset(), el_range); break; case KeyEvent.VK_LEFT: case KeyEvent.VK_KP_LEFT: editorPane.setCaretPosition(pos - el_range); break; case KeyEvent.VK_RIGHT: case KeyEvent.VK_KP_RIGHT: editorPane.setCaretPosition(pos + (el_range)); break; } } catch (BadLocationException ex) { } } }
/** Calculate the width needed to display the maximum line number */ private void setPreferredWidth() { Element root = component.getDocument().getDefaultRootElement(); int lines = root.getElementCount(); int digits = Math.max(String.valueOf(lines).length(), minimumDisplayDigits); // Update sizes when number of digits in the line number changes if (lastDigits != digits) { lastDigits = digits; FontMetrics fontMetrics = getFontMetrics(getFont()); int width = fontMetrics.charWidth('0') * digits; Insets insets = getInsets(); int preferredWidth = insets.left + insets.right + width; Dimension d = getPreferredSize(); d.setSize(preferredWidth, HEIGHT); setPreferredSize(d); setSize(d); } }
/** * Provides a mapping from the view coordinate space to the logical coordinate space of the model. * * @param fx the X coordinate >= 0 * @param fy the Y coordinate >= 0 * @param a the allocated region to render into * @return the location within the model that best represents the given point in the view >= 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 >= 0 * @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 * @see View#modelToView */ @Override public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException { // line coordinates Element map = getElement(); RSyntaxDocument doc = (RSyntaxDocument) getDocument(); int lineIndex = map.getElementIndex(pos); Token tokenList = doc.getTokenListForLine(lineIndex); Rectangle lineArea = lineToRect(a, lineIndex); tabBase = lineArea.x; // Used by listOffsetToView(). // int x = (int)RSyntaxUtilities.getTokenListWidthUpTo(tokenList, // (RSyntaxTextArea)getContainer(), // this, 0, pos); // 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); return lineArea; }
/** * Returns a token list for the <i>physical</i> line above 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 above 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 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(); 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) - 1; // if (line>=0) // return document.getTokenListForLine(line); return null; }
/** * 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; }
/* * Determine the Y offset for the current row */ private int getOffsetY(int rowStartOffset, FontMetrics fontMetrics) throws BadLocationException { // Get the bounding rectangle of the row Rectangle r = component.modelToView(rowStartOffset); int lineHeight = fontMetrics.getHeight(); int y = r.y + r.height; int descent = 0; // The text needs to be positioned above the bottom of the bounding // rectangle based on the descent of the font(s) contained on the row. if (r.height == lineHeight) { // default font is being used descent = fontMetrics.getDescent(); } else { // We need to check all the attributes for font changes if (fonts == null) { fonts = new HashMap<String, FontMetrics>(); } Element root = component.getDocument().getDefaultRootElement(); int index = root.getElementIndex(rowStartOffset); Element line = root.getElement(index); for (int i = 0; i < line.getElementCount(); i++) { Element child = line.getElement(i); AttributeSet as = child.getAttributes(); String fontFamily = (String) as.getAttribute(StyleConstants.FontFamily); Integer fontSize = (Integer) as.getAttribute(StyleConstants.FontSize); String key = fontFamily + fontSize; FontMetrics fm = fonts.get(key); if (fm == null) { Font font = new Font(fontFamily, Font.PLAIN, fontSize); fm = component.getFontMetrics(font); fonts.put(key, fm); } descent = Math.max(descent, fm.getDescent()); } } return y - descent; }
/** Returns the offset where the selection ends on the specified line. */ public int getSelectionEnd(int line) { if (line == selectionEndLine) return selectionEnd; else if (rectSelect) { Element map = document.getDefaultRootElement(); int end = selectionEnd - map.getElement(selectionEndLine).getStartOffset(); Element lineElement = map.getElement(line); int lineStart = lineElement.getStartOffset(); int lineEnd = lineElement.getEndOffset() - 1; return Math.min(lineEnd, lineStart + end); } else return getLineEndOffset(line) - 1; }
/** Returns the selected text, or null if no selection is active. */ public final String getSelectedText() { if (selectionStart == selectionEnd) return null; if (rectSelect) { // Return each row of the selection on a new line Element map = document.getDefaultRootElement(); int start = selectionStart - map.getElement(selectionStartLine).getStartOffset(); int end = selectionEnd - map.getElement(selectionEndLine).getStartOffset(); // Certain rectangles satisfy this condition... if (end < start) { int tmp = end; end = start; start = tmp; } StringBuffer buf = new StringBuffer(); Segment seg = new Segment(); for (int i = selectionStartLine; i <= selectionEndLine; i++) { Element lineElement = map.getElement(i); int lineStart = lineElement.getStartOffset(); int lineEnd = lineElement.getEndOffset() - 1; int lineLen = lineEnd - lineStart; lineStart = Math.min(lineStart + start, lineEnd); lineLen = Math.min(end - start, lineEnd - lineStart); getText(lineStart, lineLen, seg); buf.append(seg.array, seg.offset, seg.count); if (i != selectionEndLine) buf.append('\n'); } return buf.toString(); } else { return getText(selectionStart, selectionEnd - selectionStart); } }