Skip to main content

UndoManager throws javax.swing.text.StateInvariantError: infinite loop

2 replies [Last post]
seane
Offline
Joined: 2005-06-27

Hi,

I have a JTextPane with styled content, when I apply undo/redo it throws a whole bunch of exceptions and the gui stops working. I replicated the problem on both Solaris and Windows.

In order to replicat the issue, run the files provided, then type a couple of lines in the text pane and then use (CTRL+z) to undo and (CTRL+y) to redo.
1- First undo all of the modifications.
2- then start redoing by CTRL+Y
you will notice a lot of exceptions thrown. I can not figure why these exceptions are happening. To me seems like a bug.

The implementation is very simple and I can't figure why only on styled text undo/redo does not work properly. You
will also notice the strage behaviour of undo/redo.

I really appcreciate any help as my application is ready and all of a sudden I noticed that the undo/redo is not working properly.

The files are extracted from the real application and tried to eliminate alot of things. For example the component should not be opaque for some other reasons.

Regards,
Sean

Exceptions:

javax.swing.text.StateInvariantError: infinite loop in formatting
at javax.swing.text.FlowView$FlowStrategy.layout(FlowView.java:414)
at javax.swing.text.FlowView.layout(FlowView.java:182)
at javax.swing.text.BoxView.setSize(BoxView.java:379)
at javax.swing.text.BoxView.updateChildSizes(BoxView.java:348)
at javax.swing.text.BoxView.setSpanOnAxis(BoxView.java:330)
at javax.swing.text.BoxView.layout(BoxView.java:682)
at javax.swing.text.BoxView.setSize(BoxView.java:379)
at javax.swing.plaf.basic.BasicTextUI$RootView.setSize(BasicTextUI.java:1599)
at javax.swing.plaf.basic.BasicTextUI$RootView.paint(BasicTextUI.java:1318)
at javax.swing.plaf.basic.BasicTextUI.paintSafely(BasicTextUI.java:636)
at javax.swing.plaf.basic.BasicTextUI.paint(BasicTextUI.java:770)

[code]
import java.awt.*;
import java.awt.event.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.undo.*;
import javax.swing.event.*;
import java.io.*;
import java.util.*;

public class NewEditPane extends JTextPane implements DocumentListener, MouseListener,UndoableEditListener{

protected StyledDocument doc = null;
protected Segment text = new Segment();
protected int caret = 0;
protected int inputLen = 0;
protected NewJavaUtil scanner = null;
protected boolean insertHappened = false;
protected boolean removeHappend = false;
protected boolean fileRead = true;
protected Element root=null, root1 = null;
protected int line = 0, start=0;
protected Element lineElement = null;
Rectangle rectToHighlight = new Rectangle(0,0,0,0);
private boolean scanning = false; // a flag to tell the undo not to record the changes in style.
UndoManager undoManager = new UndoManager();

public NewEditPane(){
super(new DefaultStyledDocument());
setSize(1600,400);
setPreferredSize(new Dimension(1600,400));
addMouseListener(this);
doc = (StyledDocument) getDocument();
doc.addDocumentListener(this);
undoManager.setLimit(20000);
setKeys();
setOpaque(false);
setDoubleBuffered(true);
}

public void setFile(String filename){
scanner = new NewJavaUtil(this);
try{
read(new FileReader(filename), null);
}catch(IOException e){ return;}
scanAll();
invalidate();
doc.addUndoableEditListener(this);
}

public void read (Reader in, Object obj) throws IOException{
doc.removeDocumentListener(this);
super.read(in, obj);
doc = (StyledDocument) getDocument();
doc.addDocumentListener(this);
repaint();
}

public void insertUpdate(DocumentEvent e){
caret = e.getOffset();
inputLen = e.getLength();
try{
doc.getText(0, doc.getLength(), text);
}catch(BadLocationException e1){}
javax.swing.SwingUtilities.invokeLater(new Runnable(){
public void run(){
handleStyleOnInsert(caret);
}
});
}

public void undoableEditHappened(UndoableEditEvent e){
if(!scanning)
undoManager.addEdit(e.getEdit());
}

public void undo(){
try{
undoManager.undo();
} catch (CannotUndoException e){System.out.println(e);}
}

public void redo(){
try{
undoManager.redo();
} catch (CannotRedoException e){System.out.println(e);}
}

public void setKeys(){
Action undoAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
undo();
}
};
Action redoAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
redo();
}
};
NewEditPane.this.getActionMap().put("Undo",undoAction);
NewEditPane.this.getInputMap().put(KeyStroke.getKeyStroke("control Z"),"Undo");
NewEditPane.this.getActionMap().put("Redo",redoAction);
NewEditPane.this.getInputMap().put(KeyStroke.getKeyStroke("control Y"),"Redo");

}

protected void handleStyleOnInsert(int index){
if(index <= 0)
return;
scanning = true;
try{
int start = Utilities.getRowStart(NewEditPane.this, index-1);
int end = Utilities.getRowEnd(NewEditPane.this,index+inputLen);
scanner.scan(doc,text.array,start,end+1);
}catch(BadLocationException e){ System.out.println(e);}
scanning = false;
}

public void removeUpdate(DocumentEvent e){
caret = e.getOffset();
inputLen = 0;
removeHappend = true;
}

public void changedUpdate(DocumentEvent e){}

protected void paintComponent(Graphics g){
g.setColor(Color.white);
Rectangle r = getVisibleRect();
g.fillRect(r.x,r.y,r.width,r.height);
super.paintComponent(g);
}

/* scans the entire text and set the attributes. */
private void scanAll(){
text.setPartialReturn(true);
try {
doc.getText(0, doc.getLength(), text);
}catch(BadLocationException e) {
return;
}
text.setPartialReturn(true);
char[] chars = text.array;
scanner.scan(doc,chars,0,chars.length);
}

public boolean getScrollableTracksViewportWidth(){
return false;
}

public void mousePressed(MouseEvent e) {//painter();
}
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseMoved(MouseEvent e) {}
public void mouseDragged(MouseEvent e) {}

public static void main(String args[]){
NewEditPane editPane = new NewEditPane();
editPane.setFile("NewEditPane.java");
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 400);
frame.getContentPane().add(new javax.swing.JScrollPane(editPane));
frame.setVisible(true);
}
}

import javax.swing.text.StyledDocument;
import javax.swing.text.StyleConstants;
import javax.swing.text.*;
import javax.swing.JTextPane;
import java.util.HashMap;
import java.awt.Color;

public class NewJavaUtil{

private JTextPane textPane;
private static HashMap keywords = null;
private static HashMap primitiveTypes = null;
public static Style styleWord,styleKeyword,styleNumber,styleOperator,styleBracket,styleString,styleComment,
stylePrimitive,styleLineComment;
private int currLen = 0;
private StringBuffer sb;
private int cur = 0;
private boolean isNumber = false;
private Style lastSelectedAttribute;

public NewJavaUtil(JTextPane textPane){
this.textPane = textPane;
setStyles();
keywords = JavaKeywords.getKeyWords();
primitiveTypes = JavaKeywords.getPrimitiveTypes();
}

private void setStyles(){
Color c = new Color(-16777012);
Color c1 = new Color(51,51,51);
styleWord = createStyle(textPane, textPane.getForeground(),"word");
styleKeyword = createStyle(textPane, Color.blue.darker().darker(),"keyword");
styleNumber = createStyle(textPane, Color.red,"number");
styleOperator = createStyle(textPane, Color.blue,"operator");
styleBracket = createStyle(textPane, Color.blue.darker(),"bracket");
styleString = createStyle(textPane, Color.gray,"string");
styleComment = createStyle(textPane, Color.cyan.darker(),"comment");
stylePrimitive = createStyle(textPane, Color.blue,"primitive");
styleLineComment = createStyle(textPane, Color.cyan.darker(),"lineComment");
StyleConstants.setBold(styleWord, false);
StyleConstants.setBold(styleNumber, true);
StyleConstants.setBold(styleOperator, true);
StyleConstants.setBold(styleString, false);
StyleConstants.setBold(styleComment, false);
StyleConstants.setBold(styleLineComment, false);
StyleConstants.setBold(styleKeyword, true);
StyleConstants.setBold(stylePrimitive, true);
}

public static void setAttribute(StyledDocument doc, Style style, int start, int len){
if(len<=0)
return;
doc.setCharacterAttributes (start, len, style, false);
}

public static Style createStyle(JTextPane textPane, Color color, String name){
Style style = textPane.addStyle(name, null);
StyleConstants.setForeground(style, color);
return style;
}

public static boolean isKeyword(HashMap keywords, String str){
if(keywords.get(str) == null)
return false;
return true;
}

int i = 0;
char c;
char tempC = 0;
public int scan(StyledDocument doc, char[] buffer, int start, int end){
setAttribute(doc,styleWord,start,end-start);
i = start;
tempC = 0;
lastSelectedAttribute = styleWord;
if(buffer.length == 0)
return 0;
sb = new StringBuffer();
i = i+2;
try{
while(i

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
seane
Offline
Joined: 2005-06-27

Please if anybody knows anything about this issue, let me know, any suggestions (or workarounds) is greatly appreicated.

I also filed a bug. This happens on JDK 1.5 update 4. And so far nothing worked, I tried to remove the caret, I tried to explicitly call updateUI after undo/redo, but nothing worked.

Sean

priyarr
Offline
Joined: 2011-01-12

Hi Sean

Can you let me know what happened to this?
I am confronted with this problem now....please..am breaking my head...!!!!