How to trim a Document's size

I have a Swing app that displays fire alarm messages. It needs to be on all the time. Because I need to display the output in different colors (according to the alarm), I am using a StyledDocument in a jTextPane:

private JTextPane ep;

ep.setCaretPosition(0);

StyledDocument styledDoc = ep.getStyledDocument();

if (styledDocinstanceof AbstractDocument){

doc = (AbstractDocument)styledDoc;

// Add an undoableEditListener

doc.addUndoableEditListener(new MyEditListener());

} ...

If the document gets too big, I remove() its beginning:

// Keep the document to a manageable size

int docLength = doc.getLength();

if(docLength > 20000){

doc.remove(0, docLength - 20000);

}

Much to my surprise (after I used the NetBeans memory profiler), I found that all my cut text seems to be going into an undo buffer! javax.swing.text.GapContent$UndoPosRef

Which is why I added the UndoableEditListener:

publicclass MyEditListenerimplements UndoableEditListener{

public MyEditListener(){

}

publicvoid undoableEditHappened(UndoableEditEvent e){

UndoableEdit edit = e.getEdit();

edit.die();

}

}

The listener gets called after every insert and deletion, and I thought the call to die() should have removed the things from the UndoManager. But it does not.

Since my app needs to be on all the time, how do I keep my document size to a fixed size?

In general, I think the StyledDocument needs to have a method to control the amount of the undo stack.

[2334 byte] By [jamesromea] at [2007-11-26 15:39:23]
# 1
I'm not sure why you are using an UndoableEditListener to begin with. It sounds like the data is for display only, so what would you undo?Anyway, you could try taking a look at the UndoManager class. It has a setLimit(...) method that may help.
camickra at 2007-7-8 21:57:45 > top of Java-index,Desktop,Core GUI APIs...
# 2
You are correct, I do not want to undo anything. But from the Document, I see no way to access its UndoManager class.That is what I was trying to do with the listener.
jamesromea at 2007-7-8 21:57:45 > top of Java-index,Desktop,Core GUI APIs...
# 3
But if you don't add an UndoableEditListener, then I don't understand how the undo events are saved. Just get rid of the listener. (or else I don't understand how undo/redo works).
camickra at 2007-7-8 21:57:45 > top of Java-index,Desktop,Core GUI APIs...
# 4

sure you can access its undoListeners if you are using a subclass of AbstractDocument (e.g. DefaultStyledDocument or PlainDocument ).

There you can find the methods:

public UndoableEditListener[] getUndoableEditListeners()

public void removeUndoableEditListener(UndoableEditListener listener)

the12huntersa at 2007-7-8 21:57:45 > top of Java-index,Desktop,Core GUI APIs...
# 5

It doesn't matter if you don't add an UndoableEditListener. The UndoableEdit object is created and returned by the remove() and insertString() methods of the document's Content object. Then it gets added to the DocumentEvent in the handleRemove() and handleInsertString() methods of AbstractDocument. As long as there's a reference to that DocumentEvent somewhere, the UndoableEdit will continue to exist. And DocumentEvents are used all over the place.

The handleXXX() methods are package-private, so you can't override them. However, they both do a check first, and only add the UndoableEdit if it's not null. You may be able to create your own Content class that extends GapContent and returns null from its remove() and insertString() methods. The UndoableEdits will still get created, but they'll become eligible for garbage collection as soon as the method returns. public UndoableEdit insertString(int where, String str)

throws BadLocationException {

super.insertString(where, str);

return (UndoableEdit)null;

}

public UndoableEdit remove(int where, int nitems)

throws BadLocationException {

super.remove(where, nitems);

return (UndoableEdit)null;

}

You can pass an instance of your derived Content class to the appropriate constructor of the DefaultStyledDocument, then pass that document to the JTextPane constructor.

uncle_alicea at 2007-7-8 21:57:45 > top of Java-index,Desktop,Core GUI APIs...
# 6
Thats a great answer. Thanks. It really should not be this obscure to do something simple like keeping a document within bounds. It would be simple if the Document had a method to access its UndoManager.Message was edited by: jamesrome
jamesromea at 2007-7-8 21:57:45 > top of Java-index,Desktop,Core GUI APIs...
# 7

After making those changes and running for a while, javax.swing.text.GapContent$UndoPosRef is still growing. It is up to 315kB. Why is this still growing if I tell it to not do any Undos? Here is what I did....

ep = client.getOutputTextPane();

ep.setCaretPosition(0);

attrs = initAttributes(3);

StyleContext context = new StyleContext();

DefaultStyledDocument styledDoc = new DefaultStyledDocument(new MyGapContent(), context);

doc = (AbstractDocument)styledDoc;

ep.setDocument(doc);

Message was edited by:

jamesrome

jamesromea at 2007-7-8 21:57:45 > top of Java-index,Desktop,Core GUI APIs...
# 8

Well, it looks like the getPositionsInRange() method is where all those PosRef instances are created. It's also protected by null checks, so try overriding it to return null. It looks like you won't even need to call super this time.

Another possibility is to write your own implementation of the AbstractDocument.Content interface from scratch. The existing implementations are complicated by the need for liveness and undoability, neither of which matters to you.

uncle_alicea at 2007-7-8 21:57:45 > top of Java-index,Desktop,Core GUI APIs...
# 9
I'm trying it. I had 1.7 MB this morning.null
jamesromea at 2007-7-8 21:57:45 > top of Java-index,Desktop,Core GUI APIs...
# 10
That worked! Many thanks.
jamesromea at 2007-7-8 21:57:45 > top of Java-index,Desktop,Core GUI APIs...