From e8c73ce05f183eaa7fdd8ffa394739cac45bdb84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sun, 22 Apr 2018 11:21:45 +0200 Subject: [PATCH] #1456 jsyntaxpane - updated for java 9+ - fixed undomanager --- lib/jsyntaxpane-0.9.5.jar | Bin 571686 -> 572475 bytes .../java/jsyntaxpane/CompoundUndoMan.java | 219 ++-- .../main/java/jsyntaxpane/SyntaxDocument.java | 1084 +++++++++-------- 3 files changed, 701 insertions(+), 602 deletions(-) diff --git a/lib/jsyntaxpane-0.9.5.jar b/lib/jsyntaxpane-0.9.5.jar index 79d74f13d0d542aabadf2b197b9f3ac9c8210bbe..2337f742789a167a949e0864219d05397c449303 100644 GIT binary patch delta 28490 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 delta 27686 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�?-`)c19JJRp`csPqwj&S7 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 tokens; - CompoundUndoMan undo; - boolean ignoreUpdate; + public static final String CAN_UNDO = "can-undo"; + public static final String CAN_REDO = "can-redo"; - public SyntaxDocument(Lexer lexer) { - super(); - putProperty(PlainDocument.tabSizeAttribute, 4); - this.lexer = lexer; - // Listen for undo and redo events - undo = new CompoundUndoMan(this); - } + Lexer lexer; + List tokens; + CompoundUndoMan undo; - /** - * Parse the entire document and return list of tokens that do not already - * exist in the tokens list. There may be overlaps, and replacements, - * which we will cleanup later. - * @return list of tokens that do not exist in the tokens field - */ - private void parse() { - // if we have no lexer, then we must have no tokens... - if (lexer == null) { - tokens = null; - return; - } - int len = getLength(); - List toks = new ArrayList(len / 10); - long ts = System.nanoTime(); - try { - Segment seg = new Segment(); - getText(0, len, seg); - lexer.parse(seg, 0, toks); - } catch (BadLocationException ex) { - log.log(Level.SEVERE, null, ex); - } finally { - if (log.isLoggable(Level.FINEST)) { - log.finest(String.format("Parsed %d in %d ms, giving %d tokens\n", - len, (System.nanoTime() - ts) / 1000000, toks.size())); - } - tokens = toks; - } - } + boolean ignoreUpdate; + private final PropertyChangeSupport propSupport; + private boolean canUndoState = false; + private boolean canRedoState = false; - @Override - protected void fireChangedUpdate(DocumentEvent e) { - parse(); - super.fireChangedUpdate(e); - } + public SyntaxDocument(Lexer lexer) { + super(); + putProperty(PlainDocument.tabSizeAttribute, 4); + this.lexer = lexer; + // Listen for undo and redo events + undo = new CompoundUndoMan(this); + propSupport = new PropertyChangeSupport(this); + } - @Override - protected void fireInsertUpdate(DocumentEvent e) { - if (ignoreUpdate) { - return; - } - parse(); - super.fireInsertUpdate(e); - } + /** + * Parse the entire document and return list of tokens that do not already + * exist in the tokens list. There may be overlaps, and replacements, which + * we will cleanup later. + * + * @return list of tokens that do not exist in the tokens field + */ + private void parse() { + // if we have no lexer, then we must have no tokens... + if (lexer == null) { + tokens = null; + return; + } + int len = getLength(); + List toks = new ArrayList(len / 10); + long ts = System.nanoTime(); + try { + Segment seg = new Segment(); + getText(0, len, seg); + lexer.parse(seg, 0, toks); + } catch (BadLocationException ex) { + log.log(Level.SEVERE, null, ex); + } finally { + if (log.isLoggable(Level.FINEST)) { + log.finest(String.format("Parsed %d in %d ms, giving %d tokens\n", + len, (System.nanoTime() - ts) / 1000000, toks.size())); + } + tokens = toks; + } + } - @Override - protected void fireRemoveUpdate(DocumentEvent e) { - parse(); - super.fireRemoveUpdate(e); - } + @Override + protected void fireChangedUpdate(DocumentEvent e) { + parse(); + super.fireChangedUpdate(e); + } - public void setIgnoreUpdate(boolean value) { - ignoreUpdate = value; - if (!ignoreUpdate) { - parse(); - } - } + @Override + protected void fireInsertUpdate(DocumentEvent e) { + if (ignoreUpdate) { + return; + } + parse(); + super.fireInsertUpdate(e); + } - /** - * Replace the token with the replacement string - * @param token - * @param replacement - */ - public void replaceToken(Token token, String replacement) { - try { - replace(token.start, token.length, replacement, null); - } catch (BadLocationException ex) { - log.log(Level.WARNING, "unable to replace token: " + token, ex); - } - } + @Override + protected void fireRemoveUpdate(DocumentEvent e) { + parse(); + super.fireRemoveUpdate(e); + } - /** - * This class is used to iterate over tokens between two positions - * - */ - class TokenIterator implements ListIterator { + public void setIgnoreUpdate(boolean value) { + ignoreUpdate = value; + if (!ignoreUpdate) { + parse(); + } + } - int start; - int end; - int ndx = 0; + /** + * Replace the token with the replacement string + * + * @param token + * @param replacement + */ + public void replaceToken(Token token, String replacement) { + try { + replace(token.start, token.length, replacement, null); + } catch (BadLocationException ex) { + log.log(Level.WARNING, "unable to replace token: " + token, ex); + } + } - @SuppressWarnings("unchecked") - private TokenIterator(int start, int end) { - this.start = start; - this.end = end; - if (tokens != null && !tokens.isEmpty()) { - Token token = new Token(TokenType.COMMENT, start, end - start); - ndx = Collections.binarySearch((List) tokens, token); - // we will probably not find the exact token... - if (ndx < 0) { - // so, start from one before the token where we should be... - // -1 to get the location, and another -1 to go back.. - ndx = (-ndx - 1 - 1 < 0) ? 0 : (-ndx - 1 - 1); - Token t = tokens.get(ndx); - // if the prev token does not overlap, then advance one - if (t.end() <= start) { - ndx++; - } + /** + * This class is used to iterate over tokens between two positions + * + */ + class TokenIterator implements ListIterator { - } - } - } + int start; + int end; + int ndx = 0; - @Override - public boolean hasNext() { - if (tokens == null) { - return false; - } - if (ndx >= tokens.size()) { - return false; - } - Token t = tokens.get(ndx); - if (t.start >= end) { - return false; - } - return true; - } + @SuppressWarnings("unchecked") + private TokenIterator(int start, int end) { + this.start = start; + this.end = end; + if (tokens != null && !tokens.isEmpty()) { + Token token = new Token(TokenType.COMMENT, start, end - start); + ndx = Collections.binarySearch((List) tokens, token); + // we will probably not find the exact token... + if (ndx < 0) { + // so, start from one before the token where we should be... + // -1 to get the location, and another -1 to go back.. + ndx = (-ndx - 1 - 1 < 0) ? 0 : (-ndx - 1 - 1); + Token t = tokens.get(ndx); + // if the prev token does not overlap, then advance one + if (t.end() <= start) { + ndx++; + } - @Override - public Token next() { - return tokens.get(ndx++); - } + } + } + } - @Override - public void remove() { - throw new UnsupportedOperationException(); - } + @Override + public boolean hasNext() { + if (tokens == null) { + return false; + } + if (ndx >= tokens.size()) { + return false; + } + Token t = tokens.get(ndx); + if (t.start >= end) { + return false; + } + return true; + } - @Override - public boolean hasPrevious() { - if (tokens == null) { - return false; - } - if (ndx <= 0) { - return false; - } - Token t = tokens.get(ndx); - if (t.end() <= start) { - return false; - } - return true; - } + @Override + public Token next() { + return tokens.get(ndx++); + } - @Override - public Token previous() { - return tokens.get(ndx--); - } + @Override + public void remove() { + throw new UnsupportedOperationException(); + } - @Override - public int nextIndex() { - return ndx + 1; - } + @Override + public boolean hasPrevious() { + if (tokens == null) { + return false; + } + if (ndx <= 0) { + return false; + } + Token t = tokens.get(ndx); + if (t.end() <= start) { + return false; + } + return true; + } - @Override - public int previousIndex() { - return ndx - 1; - } + @Override + public Token previous() { + return tokens.get(ndx--); + } - @Override - public void set(Token e) { - throw new UnsupportedOperationException(); - } + @Override + public int nextIndex() { + return ndx + 1; + } - @Override - public void add(Token e) { - throw new UnsupportedOperationException(); - } - } + @Override + public int previousIndex() { + return ndx - 1; + } - /** - * Return an iterator of tokens between p0 and p1. - * @param start start position for getting tokens - * @param end position for last token - * @return Iterator for tokens that overal with range from start to end - */ - public Iterator getTokens(int start, int end) { - return new TokenIterator(start, end); - } + @Override + public void set(Token e) { + throw new UnsupportedOperationException(); + } - /** - * Find the token at a given position. May return null if no token is - * found (whitespace skipped) or if the position is out of range: - * @param pos - * @return - */ - public Token getTokenAt(int pos) { - if (tokens == null || tokens.isEmpty() || pos > getLength()) { - return null; - } - Token tok = null; - Token tKey = new Token(TokenType.DEFAULT, pos, 1); - @SuppressWarnings("unchecked") - int ndx = Collections.binarySearch((List) tokens, tKey); - if (ndx < 0) { - // so, start from one before the token where we should be... - // -1 to get the location, and another -1 to go back.. - ndx = (-ndx - 1 - 1 < 0) ? 0 : (-ndx - 1 - 1); - Token t = tokens.get(ndx); - if ((t.start <= pos) && (pos <= t.end())) { - tok = t; - } - } else { - tok = tokens.get(ndx); - } - return tok; - } + @Override + public void add(Token e) { + throw new UnsupportedOperationException(); + } + } - public Token getWordAt(int offs, Pattern p) { - Token word = null; - try { - Element line = getParagraphElement(offs); - if (line == null) { - return word; - } - int lineStart = line.getStartOffset(); - int lineEnd = Math.min(line.getEndOffset(), getLength()); - Segment seg = new Segment(); - getText(lineStart, lineEnd - lineStart, seg); - if (seg.count > 0) { - // we need to get the word using the words pattern p - Matcher m = p.matcher(seg); - int o = offs - lineStart; - while (m.find()) { - if (m.start() <= o && o <= m.end()) { - word = new Token(TokenType.DEFAULT, m.start() + lineStart, m.end() - m.start()); - break; - } - } - } - } catch (BadLocationException ex) { - Logger.getLogger(SyntaxDocument.class.getName()).log(Level.SEVERE, null, ex); - } finally { - return word; - } - } + /** + * Return an iterator of tokens between p0 and p1. + * + * @param start start position for getting tokens + * @param end position for last token + * @return Iterator for tokens that overal with range from start to end + */ + public Iterator getTokens(int start, int end) { + return new TokenIterator(start, end); + } - /** - * Return the token following the current token, or null - * This is an expensive operation, so do not use it to update the gui - * @param tok - * @return - */ - public Token getNextToken(Token tok) { - int n = tokens.indexOf(tok); - if ((n >= 0) && (n < (tokens.size() - 1))) { - return tokens.get(n + 1); - } else { - return null; - } - } + /** + * Find the token at a given position. May return null if no token is found + * (whitespace skipped) or if the position is out of range: + * + * @param pos + * @return + */ + public Token getTokenAt(int pos) { + if (tokens == null || tokens.isEmpty() || pos > getLength()) { + return null; + } + Token tok = null; + Token tKey = new Token(TokenType.DEFAULT, pos, 1); + @SuppressWarnings("unchecked") + int ndx = Collections.binarySearch((List) tokens, tKey); + if (ndx < 0) { + // so, start from one before the token where we should be... + // -1 to get the location, and another -1 to go back.. + ndx = (-ndx - 1 - 1 < 0) ? 0 : (-ndx - 1 - 1); + Token t = tokens.get(ndx); + if ((t.start <= pos) && (pos <= t.end())) { + tok = t; + } + } else { + tok = tokens.get(ndx); + } + return tok; + } - /** - * Return the token prior to the given token, or null - * This is an expensive operation, so do not use it to update the gui - * @param tok - * @return - */ - public Token getPrevToken(Token tok) { - int n = tokens.indexOf(tok); - if ((n > 0) && (!tokens.isEmpty())) { - return tokens.get(n - 1); - } else { - return null; - } - } + public Token getWordAt(int offs, Pattern p) { + Token word = null; + try { + Element line = getParagraphElement(offs); + if (line == null) { + return word; + } + int lineStart = line.getStartOffset(); + int lineEnd = Math.min(line.getEndOffset(), getLength()); + Segment seg = new Segment(); + getText(lineStart, lineEnd - lineStart, seg); + if (seg.count > 0) { + // we need to get the word using the words pattern p + Matcher m = p.matcher(seg); + int o = offs - lineStart; + while (m.find()) { + if (m.start() <= o && o <= m.end()) { + word = new Token(TokenType.DEFAULT, m.start() + lineStart, m.end() - m.start()); + break; + } + } + } + } catch (BadLocationException ex) { + Logger.getLogger(SyntaxDocument.class.getName()).log(Level.SEVERE, null, ex); + } finally { + return word; + } + } - /** - * This is used to return the other part of a paired token in the document. - * A paired part has token.pairValue <> 0, and the paired token will - * have the negative of t.pairValue. - * This method properly handles nestings of same pairValues, but overlaps - * are not checked. - * if The document does not contain a paired token, then null is returned. - * @param t - * @return the other pair's token, or null if nothing is found. - */ - public Token getPairFor(Token t) { - if (t == null || t.pairValue == 0) { - return null; - } - Token p = null; - int ndx = tokens.indexOf(t); - // w will be similar to a stack. The openners weght is added to it - // and the closers are subtracted from it (closers are already negative) - int w = t.pairValue; - int direction = (t.pairValue > 0) ? 1 : -1; - boolean done = false; - int v = Math.abs(t.pairValue); - while (!done) { - ndx += direction; - if (ndx < 0 || ndx >= tokens.size()) { - break; - } - Token current = tokens.get(ndx); - if (Math.abs(current.pairValue) == v) { - w += current.pairValue; - if (w == 0) { - p = current; - done = true; - } - } - } + /** + * Return the token following the current token, or null + * This is an expensive operation, so do not use it to update the gui + * + * @param tok + * @return + */ + public Token getNextToken(Token tok) { + int n = tokens.indexOf(tok); + if ((n >= 0) && (n < (tokens.size() - 1))) { + return tokens.get(n + 1); + } else { + return null; + } + } - return p; - } + /** + * Return the token prior to the given token, or null + * This is an expensive operation, so do not use it to update the gui + * + * @param tok + * @return + */ + public Token getPrevToken(Token tok) { + int n = tokens.indexOf(tok); + if ((n > 0) && (!tokens.isEmpty())) { + return tokens.get(n - 1); + } else { + return null; + } + } - /** - * Perform an undo action, if possible - */ - public void doUndo() { - if (undo.canUndo()) { - undo.undo(); - parse(); - } - } + /** + * This is used to return the other part of a paired token in the document. + * A paired part has token.pairValue <> 0, and the paired token will have + * the negative of t.pairValue. This method properly handles nestings of + * same pairValues, but overlaps are not checked. if The document does not + * contain a paired token, then null is returned. + * + * @param t + * @return the other pair's token, or null if nothing is found. + */ + public Token getPairFor(Token t) { + if (t == null || t.pairValue == 0) { + return null; + } + Token p = null; + int ndx = tokens.indexOf(t); + // w will be similar to a stack. The openners weght is added to it + // and the closers are subtracted from it (closers are already negative) + int w = t.pairValue; + int direction = (t.pairValue > 0) ? 1 : -1; + boolean done = false; + int v = Math.abs(t.pairValue); + while (!done) { + ndx += direction; + if (ndx < 0 || ndx >= tokens.size()) { + break; + } + Token current = tokens.get(ndx); + if (Math.abs(current.pairValue) == v) { + w += current.pairValue; + if (w == 0) { + p = current; + done = true; + } + } + } - /** - * Perform a redo action, if possible. - */ - public void doRedo() { - if (undo.canRedo()) { - undo.redo(); - parse(); - } - } + return p; + } - /** - * Return a matcher that matches the given pattern on the entire document - * @param pattern - * @return matcher object - */ - public Matcher getMatcher(Pattern pattern) { - return getMatcher(pattern, 0, getLength()); - } + /** + * Perform an undo action, if possible + */ + public void doUndo() { + if (undo.canUndo()) { + undo.undo(); + parse(); + } + } - /** - * Return a matcher that matches the given pattern in the part of the - * document starting at offset start. Note that the matcher will have - * offset starting from start - * - * @param pattern - * @param start - * @return matcher that MUST be offset by start to get the proper - * location within the document - */ - public Matcher getMatcher(Pattern pattern, int start) { - return getMatcher(pattern, start, getLength() - start); - } + /** + * Perform a redo action, if possible. + */ + public void doRedo() { + if (undo.canRedo()) { + undo.redo(); + parse(); + } + } - /** - * Return a matcher that matches the given pattern in the part of the - * document starting at offset start and ending at start + length. - * Note that the matcher will have - * offset starting from start - * - * @param pattern - * @param start - * @param length - * @return matcher that MUST be offset by start to get the proper - * location within the document - */ - public Matcher getMatcher(Pattern pattern, int start, int length) { - Matcher matcher = null; - if (getLength() == 0) { - return null; - } - if (start >= getLength()) { - return null; - } - try { - if (start < 0) { - start = 0; - } - if (start + length > getLength()) { - length = getLength() - start; - } - Segment seg = new Segment(); - getText(start, length, seg); - matcher = pattern.matcher(seg); - } catch (BadLocationException ex) { - log.log(Level.SEVERE, "Requested offset: " + ex.offsetRequested(), ex); - } - return matcher; - } + /** + * Return a matcher that matches the given pattern on the entire document + * + * @param pattern + * @return matcher object + */ + public Matcher getMatcher(Pattern pattern) { + return getMatcher(pattern, 0, getLength()); + } - /** - * This will discard all undoable edits - */ - public void clearUndos() { - undo.discardAllEdits(); - } + /** + * Return a matcher that matches the given pattern in the part of the + * document starting at offset start. Note that the matcher will have offset + * starting from start + * + * @param pattern + * @param start + * @return matcher that MUST be offset by start to get the proper + * location within the document + */ + public Matcher getMatcher(Pattern pattern, int start) { + return getMatcher(pattern, start, getLength() - start); + } - /** - * Gets the line at given position. The line returned will NOT include - * the line terminator '\n' - * @param pos Position (usually from text.getCaretPosition() - * @return the STring of text at given position - * @throws BadLocationException - */ - public String getLineAt(int pos) throws BadLocationException { - Element e = getParagraphElement(pos); - Segment seg = new Segment(); - getText(e.getStartOffset(), e.getEndOffset() - e.getStartOffset(), seg); - char last = seg.last(); - if (last == '\n' || last == '\r') { - seg.count--; - } - return seg.toString(); - } + /** + * Return a matcher that matches the given pattern in the part of the + * document starting at offset start and ending at start + length. Note that + * the matcher will have offset starting from start + * + * @param pattern + * @param start + * @param length + * @return matcher that MUST be offset by start to get the proper + * location within the document + */ + public Matcher getMatcher(Pattern pattern, int start, int length) { + Matcher matcher = null; + if (getLength() == 0) { + return null; + } + if (start >= getLength()) { + return null; + } + try { + if (start < 0) { + start = 0; + } + if (start + length > getLength()) { + length = getLength() - start; + } + Segment seg = new Segment(); + getText(start, length, seg); + matcher = pattern.matcher(seg); + } catch (BadLocationException ex) { + log.log(Level.SEVERE, "Requested offset: " + ex.offsetRequested(), ex); + } + return matcher; + } - /** - * Deletes the line at given position - * @param pos - * @throws javax.swing.text.BadLocationException - */ - public void removeLineAt(int pos) - throws BadLocationException { - Element e = getParagraphElement(pos); - remove(e.getStartOffset(), getElementLength(e)); - } + /** + * This will discard all undoable edits + */ + public void clearUndos() { + undo.discardAllEdits(); + } - /** - * Replace the line at given position with the given string, which can span - * multiple lines - * @param pos - * @param newLines - * @throws javax.swing.text.BadLocationException - */ - public void replaceLineAt(int pos, String newLines) - throws BadLocationException { - Element e = getParagraphElement(pos); - replace(e.getStartOffset(), getElementLength(e), newLines, null); - } + /** + * Gets the line at given position. The line returned will NOT include the + * line terminator '\n' + * + * @param pos Position (usually from text.getCaretPosition() + * @return the STring of text at given position + * @throws BadLocationException + */ + public String getLineAt(int pos) throws BadLocationException { + Element e = getParagraphElement(pos); + Segment seg = new Segment(); + getText(e.getStartOffset(), e.getEndOffset() - e.getStartOffset(), seg); + char last = seg.last(); + if (last == '\n' || last == '\r') { + seg.count--; + } + return seg.toString(); + } - /** - * Helper method to get the length of an element and avoid getting - * a too long element at the end of the document - * @param e - * @return - */ - private int getElementLength(Element e) { - int end = e.getEndOffset(); - if (end >= (getLength() - 1)) { - end--; - } - return end - e.getStartOffset(); - } + /** + * Deletes the line at given position + * + * @param pos + * @throws javax.swing.text.BadLocationException + */ + public void removeLineAt(int pos) + throws BadLocationException { + Element e = getParagraphElement(pos); + remove(e.getStartOffset(), getElementLength(e)); + } - /** - * Gets the text without the comments. For example for the string - * { // it's a comment this method will return "{ ". - * @param aStart start of the text. - * @param anEnd end of the text. - * @return String for the line without comments (if exists). - */ - public synchronized String getUncommentedText(int aStart, int anEnd) { - readLock(); - StringBuilder result = new StringBuilder(); - Iterator iter = getTokens(aStart, anEnd); - while (iter.hasNext()) { - Token t = iter.next(); - if (!TokenType.isComment(t)) { - result.append(t.getText(this)); - } - } - readUnlock(); - return result.toString(); - } + /** + * Replace the line at given position with the given string, which can span + * multiple lines + * + * @param pos + * @param newLines + * @throws javax.swing.text.BadLocationException + */ + public void replaceLineAt(int pos, String newLines) + throws BadLocationException { + Element e = getParagraphElement(pos); + replace(e.getStartOffset(), getElementLength(e), newLines, null); + } - /** - * Returns the starting position of the line at pos - * @param pos - * @return starting position of the line - */ - public int getLineStartOffset(int pos) { - return getParagraphElement(pos).getStartOffset(); - } + /** + * Helper method to get the length of an element and avoid getting a too + * long element at the end of the document + * + * @param e + * @return + */ + private int getElementLength(Element e) { + int end = e.getEndOffset(); + if (end >= (getLength() - 1)) { + end--; + } + return end - e.getStartOffset(); + } - /** - * Returns the end position of the line at pos. - * Does a bounds check to ensure the returned value does not exceed - * document length - * @param pos - * @return - */ - public int getLineEndOffset(int pos) { - int end = 0; - end = getParagraphElement(pos).getEndOffset(); - if (end >= getLength()) { - end = getLength(); - } - return end; - } + /** + * Gets the text without the comments. For example for the string + * { // it's a comment this method will return "{ ". + * + * @param aStart start of the text. + * @param anEnd end of the text. + * @return String for the line without comments (if exists). + */ + public synchronized String getUncommentedText(int aStart, int anEnd) { + readLock(); + StringBuilder result = new StringBuilder(); + Iterator iter = getTokens(aStart, anEnd); + while (iter.hasNext()) { + Token t = iter.next(); + if (!TokenType.isComment(t)) { + result.append(t.getText(this)); + } + } + readUnlock(); + return result.toString(); + } - /** - * Return the number of lines in this document - * @return - */ - public int getLineCount() { - Element e = getDefaultRootElement(); - int cnt = e.getElementCount(); - return cnt; - } + /** + * Returns the starting position of the line at pos + * + * @param pos + * @return starting position of the line + */ + public int getLineStartOffset(int pos) { + return getParagraphElement(pos).getStartOffset(); + } - /** - * Return the line number at given position. The line numbers are zero based - * @param pos - * @return - */ - public int getLineNumberAt(int pos) { - int lineNr = getDefaultRootElement().getElementIndex(pos); - return lineNr; - } + /** + * Returns the end position of the line at pos. Does a bounds check to + * ensure the returned value does not exceed document length + * + * @param pos + * @return + */ + public int getLineEndOffset(int pos) { + int end = getParagraphElement(pos).getEndOffset(); + if (end >= getLength()) { + end = getLength(); + } + return end; + } - @Override - public String toString() { - return "SyntaxDocument(" + lexer + ", " + ((tokens == null) ? 0 : tokens.size()) + " tokens)@" + - hashCode(); - } + /** + * Return the number of lines in this document + * + * @return + */ + public int getLineCount() { + Element e = getDefaultRootElement(); + int cnt = e.getElementCount(); + return cnt; + } - /** - * We override this here so that the replace is treated as one operation - * by the undomanager - * @param offset - * @param length - * @param text - * @param attrs - * @throws BadLocationException - */ - @Override - public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException { - remove(offset, length); - undo.startCombine(); - insertString(offset, text, attrs); - } + /** + * Return the line number at given position. The line numbers are zero based + * + * @param pos + * @return + */ + public int getLineNumberAt(int pos) { + int lineNr = getDefaultRootElement().getElementIndex(pos); + return lineNr; + } - /** - * Append the given string to the text of this document. - * @param str - * @return this document - */ - public SyntaxDocument append(String str) { - try { - insertString(getLength(), str, null); - } catch (BadLocationException ex) { - log.log(Level.WARNING, "Error appending str", ex); - } - return this; - } + @Override + public String toString() { + return "SyntaxDocument(" + lexer + ", " + ((tokens == null) ? 0 : tokens.size()) + " tokens)@" + + hashCode(); + } + + /** + * We override this here so that the replace is treated as one operation by + * the undomanager + * + * @param offset + * @param length + * @param text + * @param attrs + * @throws BadLocationException + */ + @Override + public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException { + remove(offset, length); + undo.startCombine(); + insertString(offset, text, attrs); + } + + /** + * Append the given string to the text of this document. + * + * @param str + * @return this document + */ + public SyntaxDocument append(String str) { + try { + insertString(getLength(), str, null); + } catch (BadLocationException ex) { + log.log(Level.WARNING, "Error appending str", ex); + } + return this; + } + + public void setCanUndo(boolean value) { + if (canUndoState != value) { + // System.out.println("canUndo = " + value); + canUndoState = value; + propSupport.firePropertyChange(CAN_UNDO, !value, value); + } + } + + public void setCanRedo(boolean value) { + if (canRedoState != value) { + // System.out.println("canRedo = " + value); + canRedoState = value; + propSupport.firePropertyChange(CAN_REDO, !value, value); + } + } // our logger instance... - private static final Logger log = Logger.getLogger(SyntaxDocument.class.getName()); + private static final Logger log = Logger.getLogger(SyntaxDocument.class.getName()); }