Why i got this exception...

i try to change the text color if user type public in my JTextPane. but i always got this exception. this is my code :

publicclass myTextPaneextends JFrameimplements CaretListener

{

StyledDocument styleDoc;

Document doc;

JTextPane textPane;

MutableAttributeSet keyWord;

public myTextPane()

{

textPane =new JTextPane();

styleDoc = textPane.getStyledDocument();

textPane.addCaretListener(this);

keyWord =new SimpleAttributeSet();

StyleConstants.setForeground(keyWord, Color.RED);

StyleConstants.setBold(keyWord,true);

JScrollPane scrollPane =new JScrollPane( textPane );

scrollPane.setPreferredSize(new Dimension( 200, 200 ) );

getContentPane().add( scrollPane );

}

publicstaticvoid main(String[] args)

{

myTextPane frame =new myTextPane();

frame.setDefaultCloseOperation( EXIT_ON_CLOSE );

frame.pack();

frame.setVisible(true);

}

publicvoid caretUpdate(CaretEvent ce)

{

try

{

if (textPane.getText().equals("public"))

{

try

{

styleDoc.insertString(styleDoc.getLength(), textPane.getText(), keyWord);

}

catch (Exception e)

{

e.printStackTrace();

}

}

}

catch (Exception e)

{

e.printStackTrace();

}

}

}

java.lang.IllegalStateException: Attempt to mutate in notification

at javax.swing.text.AbstractDocument.writeLock(Unknown Source)

at javax.swing.text.AbstractDocument.insertString(Unknown Source)

at gui.myTextPane.caretUpdate(myTextPane.java:62)

This error occurs if user already type public in my JTextPane. is there any solution for this? why i always got this exception? and how to implement something like that?

Thanks a lot.

[3119 byte] By [hudoqa] at [2007-11-26 15:21:05]
# 1

The exception occurs, because you are modifying the document while it is being modified already (i.e. typing 'public'). You can use SwingUtilities.invokeLater to avoid that, but there's plenty more to do:

public void caretUpdate(CaretEvent ce) {

if (textPane.getText().equals("public")) {

Runnable r = new Runnable() {

public void run() {

try {

String s = textPane.getText();

styleDoc.remove(0, styleDoc.getLength());

styleDoc.insertString(styleDoc.getLength(), s, keyWord);

} catch (Exception e) {

e.printStackTrace();

}

}

};

SwingUtilities.invokeLater(r);

}

}

PhHeina at 2007-7-8 11:49:39 > top of Java-index,Desktop,Core GUI APIs...
# 2

IllegalStateException - thrown on illegal lock attempt. If the document is implemented properly, this can only happen if a document listener attempts to mutate the document. This situation violates the bean event model where order of delivery is not guaranteed and all listeners should be notified before further mutations are allowed.

You should try to use the invokeLater method from SwingUtilities

ProZa at 2007-7-8 11:49:39 > top of Java-index,Desktop,Core GUI APIs...
# 3
Oups i did not saw the first reply. Sorry.
ProZa at 2007-7-8 11:49:39 > top of Java-index,Desktop,Core GUI APIs...
# 4

Hi thanks for reply PhHein. it works, but after i type public all the words after public become colored too. i just want to color only public word only, not the whole text.

What if the public type not in the 0 index of character. How to detect it?

How to implement this? for a big picture, this feature available in many IDE.

Thanks a lot.

hudoqa at 2007-7-8 11:49:39 > top of Java-index,Desktop,Core GUI APIs...
# 5

Hi' i found this code. but i think this is to complex for me. can anyone explain to me? cos i just need to match the input from user type with the keywords.

package gui;

import java.awt.Color;

import java.io.FileInputStream;

import java.io.ObjectInputStream;

import java.util.HashMap;

import javax.swing.event.DocumentEvent;

import javax.swing.text.AttributeSet;

import javax.swing.text.BadLocationException;

import javax.swing.text.DefaultEditorKit;

import javax.swing.text.DefaultStyledDocument;

import javax.swing.text.Element;

import javax.swing.text.MutableAttributeSet;

import javax.swing.text.SimpleAttributeSet;

import javax.swing.text.StyleConstants;

public class SyntaxParser extends DefaultStyledDocument

{

private DefaultStyledDocument doc;

private Element rootElement;

private boolean multiLineComment;

private MutableAttributeSet normal;

private MutableAttributeSet keyword;

private MutableAttributeSet comment;

private MutableAttributeSet quote;

private HashMap keywords = null;

public SyntaxParser() {

doc = this;

rootElement = doc.getDefaultRootElement();

putProperty(DefaultEditorKit.EndOfLineStringProperty, "\n");

normal = new SimpleAttributeSet();

StyleConstants.setForeground(normal, Color.black);

comment = new SimpleAttributeSet();

Color green = new Color(0, 200, 0);

StyleConstants.setForeground(comment, green);

//StyleConstants.setItalic(comment, true);

keyword = new SimpleAttributeSet();

Color blue = new Color(0, 0, 255);

StyleConstants.setForeground(keyword, blue);

//StyleConstants.setBold(keyword, true);

quote = new SimpleAttributeSet();

Color red = new Color(255, 0, 0);

StyleConstants.setForeground(quote, red);

//Object dummyObject = new Object();

try

{

FileInputStream fis =

new FileInputStream("Keywords.txt");

ObjectInputStream ois =

new ObjectInputStream(fis);

keywords = (HashMap)ois.readObject();

ois.close();

}

catch (Exception e)

{

}

/*

* Override to apply syntax highlighting after the document has been updated

*/

public void insertString(int offset, String str, AttributeSet a) throws BadLocationException

{

if (str.equals("{"))

str = addMatchingBrace(offset);

super.insertString(offset, str, a);

processChangedLines(offset, str.length());

}

/*

* Override to apply syntax highlighting after the document has been updated

*/

public void remove(int offset, int length) throws BadLocationException

{

super.remove(offset, length);

processChangedLines(offset, 0);

}

/*

* Determine how many lines have been changed,

* then apply highlighting to each line

*/

private void processChangedLines(int offset, int length) throws BadLocationException

{

String content = doc.getText(0, doc.getLength());

// The lines affected by the latest document update

int startLine = rootElement.getElementIndex(offset);

int endLine = rootElement.getElementIndex(offset + length);

// Make sure all comment lines prior to the start line are commented

// and determine if the start line is still in a multi line comment

setMultiLineComment(commentLinesBefore(content, startLine));

// Do the actual highlighting

for (int i = startLine; i <= endLine; i++)

applyHighlighting(content, i);

// Resolve highlighting to the next end multi line delimiter

if (isMultiLineComment())

commentLinesAfter(content, endLine);

else

highlightLinesAfter(content, endLine);

}

/*

* Highlight lines when a multi line comment is still 'open'

* (ie. matching end delimiter has not yet been encountered)

*/

private boolean commentLinesBefore(String content, int line)

{

int offset = rootElement.getElement(line).getStartOffset();

// Start of comment not found, nothing to do

int startDelimiter = lastIndexOf(content, getStartDelimiter(),

offset - 2);

if (startDelimiter < 0)

return false;

// Matching start/end of comment found, nothing to do

int endDelimiter = indexOf(content, getEndDelimiter(), startDelimiter);

if (endDelimiter < offset & endDelimiter != -1)

return false;

// End of comment not found, highlight the lines

doc.setCharacterAttributes(startDelimiter, offset - startDelimiter + 1,comment, false);

return true;

}

/*

* Highlight comment lines to matching end delimiter

*/

private void commentLinesAfter(String content, int line)

{

int offset = rootElement.getElement(line).getEndOffset();

// End of comment not found, nothing to do

int endDelimiter = indexOf(content, getEndDelimiter(), offset);

if (endDelimiter < 0)

return;

// Matching start/end of comment found, comment the lines

int startDelimiter = lastIndexOf(content, getStartDelimiter(),

endDelimiter);

if (startDelimiter < 0 || startDelimiter <= offset)

{

doc.setCharacterAttributes(offset, endDelimiter - offset + 1,

comment, false);

}

}

/*

* Highlight lines to start or end delimiter

*/

private void highlightLinesAfter(String content, int line) throws BadLocationException

{

int offset = rootElement.getElement(line).getEndOffset();

// Start/End delimiter not found, nothing to do

int startDelimiter = indexOf(content, getStartDelimiter(), offset);

int endDelimiter = indexOf(content, getEndDelimiter(), offset);

if (startDelimiter < 0)

startDelimiter = content.length();

if (endDelimiter < 0)

endDelimiter = content.length();

int delimiter = Math.min(startDelimiter, endDelimiter);

if (delimiter < offset)

return;

// Start/End delimiter found, reapply highlighting

int endLine = rootElement.getElementIndex(delimiter);

for (int i = line + 1; i < endLine; i++)

{

Element branch = rootElement.getElement(i);

Element leaf = doc.getCharacterElement(branch.getStartOffset());

AttributeSet as = leaf.getAttributes();

if (as.isEqual(comment))

applyHighlighting(content, i);

}

}

/*

* Parse the line to determine the appropriate highlighting

*/

private void applyHighlighting(String content, int line)throws BadLocationException

{

int startOffset = rootElement.getElement(line).getStartOffset();

int endOffset = rootElement.getElement(line).getEndOffset() - 1;

int lineLength = endOffset - startOffset;

int contentLength = content.length();

if (endOffset >= contentLength)

endOffset = contentLength - 1;

// check for multi line comments

// (always set the comment attribute for the entire line)

if (endingMultiLineComment(content, startOffset, endOffset) || isMultiLineComment() || startingMultiLineComment(content, startOffset, endOffset))

{

doc.setCharacterAttributes(startOffset,

endOffset - startOffset + 1, comment, false);

return;

}

// set normal attributes for the line

doc.setCharacterAttributes(startOffset, lineLength, normal, true);

// check for single line comment

int index = content.indexOf(getSingleLineDelimiter(), startOffset);

if ((index > -1) && (index < endOffset))

{

doc.setCharacterAttributes(index, endOffset - index + 1, comment,

false);

endOffset = index - 1;

}

// check for tokens

checkForTokens(content, startOffset, endOffset);

}

/*

* Does this line contain the start delimiter

*/

private boolean startingMultiLineComment(String content, int startOffset,

int endOffset) throws BadLocationException

{

int index = indexOf(content, getStartDelimiter(), startOffset);

if ((index < 0) || (index > endOffset))

return false;

else

{

setMultiLineComment(true);

return true;

}

}

/*

* Does this line contain the end delimiter

*/

private boolean endingMultiLineComment(String content, int startOffset,int endOffset) throws BadLocationException

{

int index = indexOf(content, getEndDelimiter(), startOffset);

if ((index < 0) || (index > endOffset))

return false;

else

{

setMultiLineComment(false);

return true;

}

}

/*

* We have found a start delimiter

* and are still searching for the end delimiter

*/

private boolean isMultiLineComment()

{

return multiLineComment;

}

private void setMultiLineComment(boolean value)

{

multiLineComment = value;

}

/*

* Parse the line for tokens to highlight

*/

private void checkForTokens(String content, int startOffset, int endOffset)

{

while (startOffset <= endOffset)

{

// skip the delimiters to find the start of a new token

while (isDelimiter(content.substring(startOffset, startOffset + 1)))

{

if (startOffset < endOffset)

startOffset++;

else

return;

}

// Extract and process the entire token

if (isQuoteDelimiter(content

.substring(startOffset, startOffset + 1)))

startOffset = getQuoteToken(content, startOffset, endOffset);

else

startOffset = getOtherToken(content, startOffset, endOffset);

}

}

/*

* Parse the line to get the quotes and highlight it

*/

private int getQuoteToken(String content, int startOffset, int endOffset)

{

String quoteDelimiter = content.substring(startOffset, startOffset + 1);

String escapeString = getEscapeString(quoteDelimiter);

int index;

int endOfQuote = startOffset;

// skip over the escape quotes in this quote

index = content.indexOf(escapeString, endOfQuote + 1);

while ((index > -1) && (index < endOffset))

{

endOfQuote = index + 1;

index = content.indexOf(escapeString, endOfQuote);

}

// now find the matching delimiter

index = content.indexOf(quoteDelimiter, endOfQuote + 1);

if ((index < 0) || (index > endOffset))

endOfQuote = endOffset;

else

endOfQuote = index;

doc.setCharacterAttributes(startOffset, endOfQuote - startOffset + 1,

quote, false);

return endOfQuote + 1;

}

private int getOtherToken(String content, int startOffset, int endOffset)

{

int endOfToken = startOffset + 1;

while (endOfToken <= endOffset)

{

if (isDelimiter(content.substring(endOfToken, endOfToken + 1)))

break;

endOfToken++;

}

String token = content.substring(startOffset, endOfToken);

if (isKeyword(token))

doc.setCharacterAttributes(startOffset, endOfToken - startOffset,

keyword, false);

return endOfToken + 1;

}

/*

* This updates the colored text and prepares for undo event

*/

protected void fireInsertUpdate(DocumentEvent evt)

{

super.fireInsertUpdate(evt);

try

{

processChangedLines(evt.getOffset(), evt.getLength());

}

catch (BadLocationException ex)

{

System.out.println("" + ex);

}

}

/*

* This updates the colored text and does the undo operation

*/

protected void fireRemoveUpdate(DocumentEvent evt)

{

super.fireRemoveUpdate(evt);

try

{

processChangedLines(evt.getOffset(), evt.getLength());

}

catch (BadLocationException ex)

{

System.out.println("" + ex);

}

}

/*

* Assume the needle will the found at the start/end of the line

*/

private int indexOf(String content, String needle, int offset)

{

int index;

while ((index = content.indexOf(needle, offset)) != -1)

{

String text = getLine(content, index).trim();

if (text.startsWith(needle) || text.endsWith(needle))

break;

else

offset = index + 1;

}

return index;

}

/*

* Assume the needle will the found at the start/end of the line

*/

private int lastIndexOf(String content, String needle, int offset)

{

int index;

while ((index = content.lastIndexOf(needle, offset)) != -1)

{

String text = getLine(content, index).trim();

if (text.startsWith(needle) || text.endsWith(needle))

break;

else

offset = index - 1;

}

return index;

}

private String getLine(String content, int offset)

{

int line = rootElement.getElementIndex(offset);

Element lineElement = rootElement.getElement(line);

int start = lineElement.getStartOffset();

int end = lineElement.getEndOffset();

return content.substring(start, end - 1);

}

/*

* Override for other languages

*/

protected boolean isDelimiter(String character)

{

String operands = ";:{}()[]+-/%<=>!&|^~*";

if (Character.isWhitespace(character.charAt(0))|| operands.indexOf(character) != -1)

return true;

else

return false;

}

/*

* Override for other languages

*/

protected boolean isQuoteDelimiter(String character)

{

String quoteDelimiters = "\"'";

if (quoteDelimiters.indexOf(character) < 0)

return false;

else

return true;

}

/*

* Override for other languages

*/

protected boolean isKeyword(String token)

{

Object o = keywords.get(token);

return o == null ? false : true;

}

/*

* Override for other languages

*/

protected String getStartDelimiter()

{

return "/*";

}

/*

* Override for other languages

*/

protected String getEndDelimiter()

{

return "*/";

}

/*

* Override for other languages

*/

protected String getSingleLineDelimiter()

{

return "//";

}

/*

* Override for other languages

*/

protected String getEscapeString(String quoteDelimiter)

{

return "\\" + quoteDelimiter;

}

/*

* Overide bracket matching for other languages

*/

protected String addMatchingBrace(int offset) throws BadLocationException

{

StringBuffer whiteSpace = new StringBuffer();

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 "{\n" + whiteSpace.toString() + whiteSpace.toString() + "\n"

+ whiteSpace.toString() + "}";

}

}

This code. it really works. but i don't understand about it. does this code override the insertString() method from Document? is there any better explanation?

Thanks....

hudoqa at 2007-7-8 11:49:39 > top of Java-index,Desktop,Core GUI APIs...
# 6

First it inserts the text you just typed into the Document.

Now that the Document has been updated, it parses the changed line to see if you just finished typed a reserved word. If so, then it highlights the reserved word.

That part of the processing is simple. If you only had to worry about parsing a single line of text the code would be half the size. However, in Java you need to worry about multi-line (/*...*/) comments. So most of the code attempts to determine if you just added to to a multi-line comment or not.

If your highlighting doesn't care about multi-line comments then you can easily simplify the code to only parse the current line.

camickra at 2007-7-8 11:49:39 > top of Java-index,Desktop,Core GUI APIs...
# 7
Hi' thanks for answer. i think now i got it. i already change the code to get what i want.Thanks...
hudoqa at 2007-7-8 11:49:39 > top of Java-index,Desktop,Core GUI APIs...