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); }
// TODO: make this a method of SikuliDocument, no need to pass document as argument private void changeIndentation(DefaultStyledDocument doc, int linenum, int columns) throws BadLocationException { PreferencesUser pref = PreferencesUser.getInstance(); boolean expandTab = pref.getExpandTab(); int tabWidth = pref.getTabWidth(); if (linenum < 0) { throw new BadLocationException("Negative line", -1); } Element map = doc.getDefaultRootElement(); if (linenum >= map.getElementCount()) { throw new BadLocationException("No such line", doc.getLength() + 1); } if (columns == 0) { return; } Element lineElem = map.getElement(linenum); int lineStart = lineElem.getStartOffset(); int lineLength = lineElem.getEndOffset() - lineStart; String line = doc.getText(lineStart, lineLength); // determine current indentation and number of whitespace characters int wsChars; int indentation = 0; for (wsChars = 0; wsChars < line.length(); wsChars++) { char c = line.charAt(wsChars); if (c == ' ') { indentation++; } else if (c == '\t') { indentation += tabWidth; } else { break; } } int newIndentation = indentation + columns; if (newIndentation <= 0) { doc.remove(lineStart, wsChars); return; } // build whitespace string for new indentation StringBuilder newWs = new StringBuilder(newIndentation / tabWidth + tabWidth - 1); int ind = 0; if (!expandTab) { for (; ind + tabWidth <= newIndentation; ind += tabWidth) { newWs.append('\t'); } } for (; ind < newIndentation; ind++) { newWs.append(' '); } doc.replace(lineStart, wsChars, newWs.toString(), null); }
/** * 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 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. }
public void appendToEnd(String text) { Element root = document.getDefaultRootElement(); try { document.insertAfterEnd(root.getElement(root.getElementCount() - 1), text); } catch (BadLocationException e) { logger.error("Insert in the HTMLDocument failed.", e); } catch (IOException e) { logger.error("Insert in the HTMLDocument failed.", e); } }
/** * Returns the last child of <code>parent</code> that is a leaf. If the last child is a not a * leaf, this method is called with the last child. */ private Element getDeepestLeaf(Element parent) { if (parent.isLeaf()) { return parent; } int childCount = parent.getElementCount(); if (childCount == 0) { return parent; } return getDeepestLeaf(parent.getElement(childCount - 1)); }
/* */ protected void loadChildren(ViewFactory paramViewFactory) /* */ { /* 261 */ Element localElement = getElement(); /* 262 */ int i = localElement.getElementCount(); /* 263 */ if (i > 0) { /* 264 */ View[] arrayOfView = new View[i]; /* 265 */ for (int j = 0; j < i; j++) { /* 266 */ arrayOfView[j] = new WrappedLine(localElement.getElement(j)); /* */ } /* 268 */ replace(0, 0, arrayOfView); /* */ } /* */ }
public int getLineStartOffset(int line) throws BadLocationException { // line starting from 0 Element map = getDocument().getDefaultRootElement(); if (line < 0) { throw new BadLocationException("Negative line", -1); } else if (line >= map.getElementCount()) { throw new BadLocationException("No such line", getDocument().getLength() + 1); } else { Element lineElem = map.getElement(line); return lineElem.getStartOffset(); } }
/** * Fetches the first element. * * @return an Element. */ public Element first() { // just in case... if (root == null) { return null; } elementStack = new Stack(); if (root.getElementCount() != 0) { elementStack.push(new StackItem(root)); } return root; }
/** * 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); }
/** * Fetches the next Element. The strategy used to locate the next element is a depth-first search. * * @return the next element or <code>null</code> at the end of the list. */ public Element next() { /* if current() has not been invoked and next is invoked, the very first element will be returned. */ if (elementStack == null) { return first(); } // no more elements if (elementStack.isEmpty()) { return null; } // get a handle to the element on top of the stack StackItem item = (StackItem) elementStack.peek(); Element elem = item.getElement(); int index = item.getIndex(); if (index + 1 < elem.getElementCount()) { Element child = elem.getElement(index + 1); if (child.isLeaf()) { /* In this case we merely want to increment the child index of the item on top of the stack.*/ item.incrementIndex(); } else { /* In this case we need to push the child(branch) on the stack so that we can iterate over its children. */ elementStack.push(new StackItem(child)); } return child; } else { /* No more children for the item on top of the stack therefore pop the stack. */ elementStack.pop(); if (!elementStack.isEmpty()) { /* Increment the child index for the item that is now on top of the stack. */ StackItem top = (StackItem) elementStack.peek(); top.incrementIndex(); /* We now want to return its next child, therefore call next() recursively. */ return next(); } } return null; }
/** * 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; } } }
/** * 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); } }
private void parse(Element node) { if (!showThumbs) { // do not show any thumbnails return; } int count = node.getElementCount(); for (int i = 0; i < count; i++) { Element elm = node.getElement(i); Debug.log(8, elm.toString()); if (elm.isLeaf()) { int start = elm.getStartOffset(), end = elm.getEndOffset(); parseRange(start, end); } else { parse(elm); } } }
/** * 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)); }
/* * 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; }
/** 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); } }
public boolean reparseCheckContent() { Element e = this.getDocument().getDefaultRootElement(); String txt; if (e.getElementCount() > 2) { return false; } else if (e.getElement(1).getEndOffset() - e.getElement(1).getStartOffset() > 1) { return false; } else { int is = e.getElement(0).getStartOffset(); int ie = e.getElement(0).getEndOffset(); try { txt = e.getElement(0).getDocument().getText(is, ie - 1); if (txt.endsWith(Settings.TypeCommentToken)) { return true; } } catch (BadLocationException ex) { return false; } } return false; }
private int getFunctionStartOffset(String func, Element node) throws BadLocationException { Document doc = getDocument(); int count = node.getElementCount(); Pattern patDef = Pattern.compile("def\\s+" + func + "\\s*\\("); for (int i = 0; i < count; i++) { Element elm = node.getElement(i); if (elm.isLeaf()) { int start = elm.getStartOffset(), end = elm.getEndOffset(); String line = doc.getText(start, end - start); Matcher matcher = patDef.matcher(line); if (matcher.find()) { return start; } } else { int p = getFunctionStartOffset(func, elm); if (p >= 0) { return p; } } } return -1; }
/** * 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; }
/** * 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); }