jQuery in Action, 2nd edition*
The moose likes Swing / AWT / SWT and the fly likes Help with UndoManager Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Murach's Java Servlets and JSP this week in the Servlets forum!
JavaRanch » Java Forums » Java » Swing / AWT / SWT
Bookmark "Help with UndoManager" Watch "Help with UndoManager" New topic
Author

Help with UndoManager

Gary Newcombe
Greenhorn

Joined: Oct 26, 2003
Posts: 1
Thanks for reading!
I have made a small app to illustrate the problem I am having. I have a JTextArea which I have an UndoManager managing any edits made. But, I get an ArrayIndexOutOfBoundsException - sometimes, but then not other times.
At the end of this post:-
UndoManager.java - compiles to illustrate problem
Stack Trace - for ArrayIndexOutOfBoundsException
Compile and press the 'Test Me' button first, then 'Undo' and this causes the exception. If you change the code in the actionPerformed method, you will see that there is not always an exception.
I have traced the error, and it seems to occur if the first edit to the JTextArea ends in a newline char, and also, if the first edit consists of more than one line and the first line is shorter than any of the others eg.

String s = "a\nab\n"; // this CAUSES an exception
If the first line length >= the second, it is fine eg.
String s = "ab\nab\n"; // this does NOT cause an exception
My question is: what am I doing wrong? Must be something simple?
PS. I have tried with various different methods, eg dsd.insertString(...) etc and regardless, I get the same error every time.
Can you tell me what I'm doing wrong???
Much appreciated!
**************************************************************************
Here is the Code:
**************************************************************************
/* Small app to test UndoManager
*
* Works fine for straight editing in the JTextArea,
* but if you apply a few methods on the Text Area, using
* the class API, it starts to throw ArrayIndexOutOfBoundsExceptions.
*
* My question is this: What do I need to do to make it possible to undo
* textArea.setText(...) or textArea.append(...) methods from code. I have
* tried different methods, eg dsd.insertText(...) etc, but always the same
* result.
*
* I have set this example up with some data. If you execute the code, hit
* the test button FIRST before typing in anything, then undo, and you get the
* exception. This exception only occurs if the first line of the append is
* shorter than the others, and the whole append all ends in a newline char!
* Other strange things happen too!
*
* Have a look at the actionPerformed method. Play around too. Strange things.
*
* I know I must be doing something simple wrong!!!
*/
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.undo.*;
import javax.swing.text.*;

public class UndoManagerTest extends JFrame implements ActionListener
{
private JPanel contentPane;
private JTextArea textArea;
private JButton undoButton, redoButton, testButton;
private UndoManager undo;
private UndoAction undoAction;
private RedoAction redoAction;
private DefaultStyledDocument dsd;
//--------------------------------------------------------------------------
public UndoManagerTest()
{
contentPane = new JPanel();
dsd = new DefaultStyledDocument();
textArea = new JTextArea( dsd, "", 20, 30 );
JScrollPane scrollPane = new JScrollPane( textArea );
dsd.addUndoableEditListener( new MyUndoableEditListener() );

undoAction = new UndoAction ( "Undo" );
redoAction = new RedoAction ( "Redo" );
undoButton = new JButton( undoAction );
redoButton = new JButton( redoAction );
testButton = new JButton( "Test Me" );
testButton.addActionListener( this );

contentPane.add( scrollPane );
contentPane.add( undoButton );
contentPane.add( redoButton );
contentPane.add( testButton );
setContentPane( contentPane );
// create a new UndoManager
undo = new UndoManager();
}
//--------------------------------------------------------------------------
public void actionPerformed( ActionEvent e )
{
if( e.getSource() == testButton )
{
String s = "a\nab\n"; // this CAUSES an exception
//String s = "ab\nab\n"; // this does NOT cause an exception
//String s = "a\na"; // this does NOT cause an exception
textArea.append( s );
}
}
//--------------------------------------------------------------------------
private class UndoAction extends AbstractAction
{
public UndoAction( String text )
{
super( text );
setEnabled( false );
}
public void actionPerformed( ActionEvent e )
{
try {
undo.undo();
}
catch( CannotUndoException ex )
{
System.out.println( "Unable to undo: " + ex);
ex.printStackTrace();
}
catch( Exception ec )
{
System.err.println( "UndoAction General Exception: Why this error???" );
ec.printStackTrace();
}
updateUndoState();
redoAction.updateRedoState();
}
protected void updateUndoState()
{
if( undo.canUndo() )
{
setEnabled( true );
}
else
{
setEnabled( false );
}
}
}
//--------------------------------------------------------------------------
private class RedoAction extends AbstractAction
{
public RedoAction( String text )
{
super( text );
setEnabled( false );
}
public void actionPerformed( ActionEvent e )
{
try {
undo.redo();
}
catch ( CannotRedoException ex )
{
System.out.println("Unable to redo: " + ex);
ex.printStackTrace();
}
catch( Exception ec )
{
System.err.println( Action.NAME + " Why this error???" );
ec.printStackTrace();
}
updateRedoState();
undoAction.updateUndoState();
}
protected void updateRedoState()
{
if ( undo.canRedo() )
{
setEnabled( true );
}
else
{
setEnabled( false );
}
}
}
//--------------------------------------------------------------------------
// Listener for undo manager
protected class MyUndoableEditListener implements UndoableEditListener
{
public void undoableEditHappened( UndoableEditEvent e )
{
//Remember the edit and update the menus
undo.addEdit( e.getEdit() );
undoAction.updateUndoState();
redoAction.updateRedoState();
}
}
//--------------------------------------------------------------------------
public static void main( String[] args )
{
UndoManagerTest mainFrame = new UndoManagerTest();
mainFrame.setSize( 400, 400 );
mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
mainFrame.setTitle( "UndoManager Test" );
mainFrame.setVisible( true );
}
//--------------------------------------------------------------------------
}
***************************************************************************
Here is the Stack Trace:
***************************************************************************
java.lang.ArrayIndexOutOfBoundsException: -1
at javax.swing.text.AbstractDocument$BranchElement.getEndOffset(AbstractDocument.java:2333)
at javax.swing.text.PlainView.getLineWidth(PlainView.java:631)
at javax.swing.text.PlainView.updateDamage(PlainView.java:507)
at javax.swing.text.PlainView.removeUpdate(PlainView.java:434)
at javax.swing.plaf.basic.BasicTextUI$RootView.removeUpdate(BasicTextUI.java:1501)
at javax.swing.plaf.basic.BasicTextUI$UpdateHandler.removeUpdate(BasicTextUI.java:1741)
at javax.swing.text.AbstractDocument.fireRemoveUpdate(AbstractDocument.java:242)
at javax.swing.text.AbstractDocument$DefaultDocumentEvent.undo(AbstractDocument.java:2799)
at javax.swing.undo.UndoManager.undoTo(UndoManager.java:210)
at javax.swing.undo.UndoManager.undo(UndoManager.java:275)
at UndoManagerTest$UndoAction.actionPerformed(UndoManagerTest.java:107)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1786)
at javax.swing.AbstractButton$ForwardActionEvents.actionPerformed(AbstractButton.java:1839)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:420)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:258)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:245)
at java.awt.Component.processMouseEvent(Component.java:5100)
at java.awt.Component.processEvent(Component.java:4897)
at java.awt.Container.processEvent(Container.java:1569)
at java.awt.Component.dispatchEventImpl(Component.java:3615)
at java.awt.Container.dispatchEventImpl(Container.java:1627)
at java.awt.Component.dispatchEvent(Component.java:3477)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:3483)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3198)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3128)
at java.awt.Container.dispatchEventImpl(Container.java:1613)
at java.awt.Window.dispatchEventImpl(Window.java:1606)
at java.awt.Component.dispatchEvent(Component.java:3477)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:456)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:145)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:137)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:100)
 
It is sorta covered in the JavaRanch Style Guide.
 
subject: Help with UndoManager
 
Similar Threads
undoProblem
Invoking DLL from a Swing GUI
mousePressProblem
About Undo!
Exception Null