Search code examples
javaswingjtextpaneillegalstateexception

When updating attribute set of word it throw IllegalStateException in JTextPane


In my program I have text pane. In which when I entered text in text pane it change the color of only java keyword in blue. my program selected the word properly but when I attempting to set attribute on word it throws IllegalStateException How can I resolve it ?

package event;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;

import javax.swing.text.StyledDocument;

public class SourceCodeWriter implements DocumentListener, KeyListener{
  JTextPane pane;
  public static JPanel contentPane;
  public static JFrame frame;
  int poistion = 0;
  int start = 0;
  int set = 0;
  int lock = 0;
  int count = 0;
  int endPos = 0;
  char key;
  String word =  "";
  List<String> keywordList = new ArrayList<String>();
  public SourceCodeWriter() {
  }
  public JPanel createContentPane() {
    JPanel panel = new JPanel(new BorderLayout());
    pane = new JTextPane();

    pane.addKeyListener(this);
    pane.getStyledDocument().addDocumentListener(this);
    pane.setFont(new Font("Lucida Console",Font.BOLD,20));

    panel.add(pane);
    return panel;
  }
  @Override
  public void changedUpdate(DocumentEvent e) {

  }
  @Override
  public void insertUpdate(DocumentEvent e) {
    if(key != '\n') {
      word = word + key;
    }
    if(key == ' ' || (int)key == 10) {
      set = 0;
      lock = 0;
      word = "";
    }
    if(lock == 1) {
      endPos = e.getDocument().getLength();
    }
    if(keywordList.contains(word.trim())){
      System.out.println("contains :"+word);
      update(poistion,endPos-poistion,e);
    }
    if(lock == 0) {
      poistion = count ;
      lock = 1;
    }
    count++;
  }
  /**
   * This method update the attribute set of java keyword word 
   * @param start starting position of the word
   * @param length length of the word
   * @param event document event on document where we change the attribute set
   */
  public void update(int start,int length,DocumentEvent event) {
    try {
      System.out.println("Word : "+event.getDocument().getText(start, length)+ " #Position : Start : "+start+" end : "+(start+length));;
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    SimpleAttributeSet set = new SimpleAttributeSet();
    StyleConstants.setForeground(set, Color.blue);
    StyledDocument style = pane.getStyledDocument();
    style.setCharacterAttributes(start, length, set, true);
  }
  @Override
  public void removeUpdate(DocumentEvent e) {
    // TODO Auto-generated method stub

  }
  public static void createAndShowGUI() {
    JFrame.setDefaultLookAndFeelDecorated(true);
    frame =  new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    SourceCodeWriter obj = new SourceCodeWriter();
    obj.loadKeywordList();

    contentPane = obj.createContentPane();
    frame.setContentPane(contentPane);

    frame.setVisible(true);
    frame.setSize(400,400);
  }
  public static void main(String[] args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
          createAndShowGUI();
      }
    });
  }
  @Override
  public void keyPressed(KeyEvent e) {
    // TODO Auto-generated method stub

  }
  @Override
  public void keyReleased(KeyEvent e) {
    // TODO Auto-generated method stub

  }
  @Override
  public void keyTyped(KeyEvent e) {
    key = e.getKeyChar();

  }
  /** 
   * This method is used to load all Keyword in java in list from a txt file. 
   */
  public void loadKeywordList() {
    File keywordFile = new File("D:/JavaKeywordList.txt");
    String line ="";
    try {
      BufferedReader reader = new BufferedReader(new FileReader(keywordFile));
      while((line = reader.readLine()) != null) {
        keywordList.add(line.trim());
      }
    }
    catch(IOException e) {
      e.printStackTrace();
    }
  }
}

And the Exeption Log :

Exception in thread "AWT-EventQueue-0" Word : int #Position : Start : 0 end : 3
java.lang.IllegalStateException: Attempt to mutate in notification
    at javax.swing.text.AbstractDocument.writeLock(Unknown Source)
    at javax.swing.text.DefaultStyledDocument.setCharacterAttributes(Unknown Source)
    at event.SourceCodeWriter.update(SourceCodeWriter.java:96)
    at event.SourceCodeWriter.insertUpdate(SourceCodeWriter.java:72)
    at javax.swing.text.AbstractDocument.fireInsertUpdate(Unknown Source)
    at javax.swing.text.AbstractDocument.handleInsertString(Unknown Source)
    at javax.swing.text.AbstractDocument.insertString(Unknown Source)
    at javax.swing.text.AbstractDocument.replace(Unknown Source)
    at javax.swing.JTextPane.replaceSelection(Unknown Source)
    at javax.swing.JTextPane.replaceSelection(Unknown Source)
    at javax.swing.text.DefaultEditorKit$DefaultKeyTypedAction.actionPerformed(Unknown Source)
    at javax.swing.SwingUtilities.notifyAction(Unknown Source)
    at javax.swing.JComponent.processKeyBinding(Unknown Source)
    at javax.swing.JComponent.processKeyBindings(Unknown Source)
    at javax.swing.JComponent.processKeyEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.KeyboardFocusManager.redispatchEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$500(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

Solution

  • Change your code in updateMethod() as ,

    StyledDocument style = pane.getStyledDocument();
    Runnable runnable = new Runnable() {
            @Override
            public void run() {
                style.setCharacterAttributes(start, length, set, true);
            }
        };
        SwingUtilities.invokeLater(runnable);