views:

46

answers:

3

I have a text field in my application. Despite it being a text field, users sometimes paste huge amounts of text into it. Additionally, other functions of the problem set large amounts in as well.

Sometimes there is so much text that the JVM gets an access violation in fontmanager.dll. Oracle doesn't appear to be interested in fixing the problem itself, so I would like to at least try to avoid it.

Limiting the amount of text the user inputs is apparently not acceptable (otherwise this would be the most obvious solution) but it's acceptable to allow it to be set and then disable the text field. When the text is bound back to the model, it should contain the full text again.

Since this is inherently a bug in the view, I figured that the fix should be in the view, as opposed to working around it in the model and adding the additional properties there.

My first attempt went something like this:

public class LimitedTextField extends JTextField {
    static final int LIMIT = 10000;
    private String fullString;

    @Override
    public void setText(String text) {
        if (text != null && text.length() > LIMIT) {
            fullString = text;
            setEnabled(false);
        } else {
            fullString = null;
            super.setText(text);
            setEnabled(true);
        }
    }

    @Override
    public String getText() {
        if (fullString != null) {
            return fullString;
        } else {
            return super.getText();
        }
    }
}

This does pass naive unit tests, but once I wrote an additional test for BeansBinding, I found that it didn't work because BeansBinding doesn't bind to the text property but rather binds to the Document, simulating a text property. So actually getText() always returns an empty string on that test.

I am now looking at trying to make a Document implementation which will do what I want, but it sure isn't easy to do this kind of trick at the document level. I can see all the methods it has, but I can't find a good way to limit the text without also making that text unavailable when calling getText().

+1  A: 

This is a tough one no doubt. You want to affect the painting of the field with minimal impact other than not trying to render too much text. The only suggestion I have is to look at creating your own painting strategy (see http://forums.sun.com/thread.jspa?threadID=481290) and where the text is drawn, just draw a sub-set of the characters. You could look at trying to build a new UIDelegate for drawing the text component but that might be pretty hard too. This painting overview might help steer you with regards to custom painting. This article might help you with how to apply a custom UI delegate across all textfields or just the one you are trying to correct.

jowierun
+1  A: 

Instead of using a JTextField maybe you could use a sinlge line JTextArea. Then you can insert a newline character into the Document. Then when the text is painted you will only see a single line.

You will probably need to override the getText() method as well to remove the newline character. Not sure if it helps but it may get you thinking in a different direction.

camickr
A: 

The Limited Length Document is really easy to do. Of course there are several approches, Here is the simplest (works in production in our environment):

package com.twist.ui.text.document;

import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

public class LimitedLengthDocument extends PlainDocument {
    private static final long serialVersionUID = 1L;

    private int limit;

    public LimitedLengthDocument(int limit) {
        super();
        this.limit = limit;
    }

    public void insertString(int offset, String str, AttributeSet attr) throws BadLocationException {
        if (str == null)
            return;

        // insert the string as usual.
        super.insertString(offset, str, attr);

        // If user tries to paste in a String that will not fit into the textfield, this approach will 
        // insert the text and remove the extra characters from the right.      

        // if resultant doc length is greater than the allowable size, truncate the document.
        if( getLength() > limit  )
            super.remove(limit, getLength() - limit);
    }
}
eugener