-
Bug
-
Resolution: Not an Issue
-
P4
-
None
-
1.4.2
-
x86
-
windows_2000
FULL PRODUCT VERSION :
java version "1.4.2_06"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_06-b03)
Java HotSpot(TM) Client VM (build 1.4.2_06-b03, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows 2000 [Version 5.00.2195]
A DESCRIPTION OF THE PROBLEM :
Overwrite mode cannot be changed in DefaultFormatter when DocumentFilter is set. This is true for JFormattedTextFields.
I would like to restrict the user's possibility to enter characters to a limit of say 10. Furthermore I would like to do some formatting. Therefore I subclass DefaultFormatter, overwrite "protected DocumentFilter getDocumentFilter()" and make that method return my own LimitedLengthDocumentFilter.
Then I try to toggle the OverwiteMode of the Formatter at runtime. I enter text into the TextField and see that the overwrite mode is not changed. It is always insert-mode.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached program, comment/ uncomment the line where the documentFilter is set and enter text into The textfield.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Overwrite mode should be changeable independently of the presence of a custom DocumentFilter.
ACTUAL -
Overwrite mode does not toggle
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.JPanel;
import javax.swing.JFormattedTextField;
import javax.swing.JTextField;
import javax.swing.text.DefaultFormatter;
import javax.swing.text.DocumentFilter;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import java.awt.HeadlessException;
import java.awt.Toolkit;
import java.text.ParseException;
public class MainFrame extends JFrame {
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (Exception e) {
e.printStackTrace();
}
new MainFrame();
}
public MainFrame() throws HeadlessException {
init();
}
private void init() {
this.setSize(400, 250);
this.setLocation(100, 100);
this.setTitle("Test");
JPanel lPanel = new JPanel();
lPanel.setLayout(null);
this.getContentPane().add(lPanel);
//Formatter
LimitedLengthFormatter lFormatter = new LimitedLengthFormatter(10);
FormattedTextField lTextField = new FormattedTextField(lFormatter);
//Comment/ uncomment the following line to produce the effect:
//lFormatter.setFilter(new LimitedLengthDocumentFilter(10, lTextField));
lTextField.toggleOverwriteMode();
lTextField.setBounds(20, 20, 120, 26);
JTextField lSecondField = new JTextField();
lSecondField.setBounds(20, 60, 120, 26);
lPanel.add(lTextField);
lPanel.add(lSecondField);
this.setVisible(true);
}
class LimitedLengthFormatter extends DefaultFormatter {
private int mLength;
private DocumentFilter mFilter;
public LimitedLengthFormatter(int pLength) {
setOverwriteMode(false);
setAllowsInvalid(true);
setCommitsOnValidEdit(true);
mLength = pLength;
}
//Takes the contents of the field and creates an appropriate object
//Invoked every time a text is entered into the textfield!
public Object stringToValue(String string) throws ParseException {
if (string.length() > mLength) {
Toolkit.getDefaultToolkit().beep();
//removeSurplus();
return string.substring(0, mLength);
}
else {
setEditValid(true);
return super.stringToValue(string);
}
}
//Cut off everything longer than defined by mLength
private void removeSurplus() {
JFormattedTextField ftf = getFormattedTextField();
ftf.setText(ftf.getText().substring(0, mLength));
}
//Takes an object and creates a String-representation
public String valueToString(Object value) throws ParseException {
if (value != null && value.toString().length() >= mLength) {
invalidEdit();
return value.toString().substring(0, mLength);
}
else {
return super.valueToString(value);
}
}
void commitEdit() throws ParseException {
JFormattedTextField ftf = getFormattedTextField();
if (ftf != null && ftf.getText().length() < mLength) {
ftf.commitEdit();
}
}
protected DocumentFilter getDocumentFilter() {
if (mFilter == null) {
return super.getDocumentFilter();
}
else {
return mFilter;
}
}
public void setFilter(DocumentFilter pFilter) {
mFilter = pFilter;
}
}
class FormattedTextField extends JFormattedTextField {
private boolean mOverwriteMode = false;
private JFormattedTextField.AbstractFormatter mFormatter;
public FormattedTextField() {
}
public FormattedTextField(JFormattedTextField.AbstractFormatterFactory factory) {
super(factory);
}
public FormattedTextField(JFormattedTextField.AbstractFormatterFactory factory, Object currentValue) {
super(factory, currentValue);
}
public FormattedTextField(java.text.Format format) {
super(format);
}
public FormattedTextField(JFormattedTextField.AbstractFormatter formatter) {
super(formatter);
mFormatter = formatter;
}
public FormattedTextField(Object value) {
super(value);
}
public void toggleOverwriteMode() {
mOverwriteMode = !mOverwriteMode;
((DefaultFormatter) mFormatter).setOverwriteMode(mOverwriteMode);
System.out.println("Überschreibe-Modus= " + mOverwriteMode);
}
}
class LimitedLengthDocumentFilter extends DocumentFilter {
private final int mLimit;
private final JFormattedTextField mTextField;
public LimitedLengthDocumentFilter(int pLimit, JFormattedTextField pTextField) {
mLimit = pLimit;
mTextField = pTextField;
}
/**
* This method is always chosen because the documents used are derived from AbstractDocument
* and calls to setText on a JTextComponent then calls this method.
*/
public void replace(DocumentFilter.FilterBypass fb,
int offset,
int length,
String text,
AttributeSet attrs) throws BadLocationException {
if ((text != null) && (!"".equals(text))) {
//setting limit to -1 sets the field to umlimited.
if (mLimit == -1) {
super.replace(fb, offset, length, text, attrs);
}
else {
String lPreviousText = fb.getDocument().getText(0, fb.getDocument().getLength());
if (lPreviousText.concat(text).length() <= mLimit) {
super.replace(fb, offset, length, text, attrs);
}
else { //The resulting string would be longer than lLimit: truncate the string
if (mTextField.getSelectedText() == null) {
//No text selected -> paste as much text as possible and beep
if (lPreviousText.length() < mLimit) {
String lTruncatedText = text.substring(0, (mLimit - lPreviousText.length()));
super.replace(fb, offset, length, lTruncatedText, attrs);
}
Toolkit.getDefaultToolkit().beep();
}
//there was a selection:
else {
//If the result of the replacement of the selection still fits with the limit:
//do the replacement
if (fb.getDocument().getLength() + text.length() - mTextField.getSelectedText().length() <= mLimit) {
super.replace(fb, offset, length, text, attrs);
}
//The resulting contents would be too long:
else {
//Do the replacement, but truncate the new text to the lengh of the selection and beep.
String lTruncatedText = text.substring(0, mTextField.getSelectedText().length());
super.replace(fb, offset, length, lTruncatedText, attrs);
Toolkit.getDefaultToolkit().beep();
}
}
}
}
}
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Not found yet.
Documented in Release Notes.
java version "1.4.2_06"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_06-b03)
Java HotSpot(TM) Client VM (build 1.4.2_06-b03, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows 2000 [Version 5.00.2195]
A DESCRIPTION OF THE PROBLEM :
Overwrite mode cannot be changed in DefaultFormatter when DocumentFilter is set. This is true for JFormattedTextFields.
I would like to restrict the user's possibility to enter characters to a limit of say 10. Furthermore I would like to do some formatting. Therefore I subclass DefaultFormatter, overwrite "protected DocumentFilter getDocumentFilter()" and make that method return my own LimitedLengthDocumentFilter.
Then I try to toggle the OverwiteMode of the Formatter at runtime. I enter text into the TextField and see that the overwrite mode is not changed. It is always insert-mode.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached program, comment/ uncomment the line where the documentFilter is set and enter text into The textfield.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Overwrite mode should be changeable independently of the presence of a custom DocumentFilter.
ACTUAL -
Overwrite mode does not toggle
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.JPanel;
import javax.swing.JFormattedTextField;
import javax.swing.JTextField;
import javax.swing.text.DefaultFormatter;
import javax.swing.text.DocumentFilter;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import java.awt.HeadlessException;
import java.awt.Toolkit;
import java.text.ParseException;
public class MainFrame extends JFrame {
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (Exception e) {
e.printStackTrace();
}
new MainFrame();
}
public MainFrame() throws HeadlessException {
init();
}
private void init() {
this.setSize(400, 250);
this.setLocation(100, 100);
this.setTitle("Test");
JPanel lPanel = new JPanel();
lPanel.setLayout(null);
this.getContentPane().add(lPanel);
//Formatter
LimitedLengthFormatter lFormatter = new LimitedLengthFormatter(10);
FormattedTextField lTextField = new FormattedTextField(lFormatter);
//Comment/ uncomment the following line to produce the effect:
//lFormatter.setFilter(new LimitedLengthDocumentFilter(10, lTextField));
lTextField.toggleOverwriteMode();
lTextField.setBounds(20, 20, 120, 26);
JTextField lSecondField = new JTextField();
lSecondField.setBounds(20, 60, 120, 26);
lPanel.add(lTextField);
lPanel.add(lSecondField);
this.setVisible(true);
}
class LimitedLengthFormatter extends DefaultFormatter {
private int mLength;
private DocumentFilter mFilter;
public LimitedLengthFormatter(int pLength) {
setOverwriteMode(false);
setAllowsInvalid(true);
setCommitsOnValidEdit(true);
mLength = pLength;
}
//Takes the contents of the field and creates an appropriate object
//Invoked every time a text is entered into the textfield!
public Object stringToValue(String string) throws ParseException {
if (string.length() > mLength) {
Toolkit.getDefaultToolkit().beep();
//removeSurplus();
return string.substring(0, mLength);
}
else {
setEditValid(true);
return super.stringToValue(string);
}
}
//Cut off everything longer than defined by mLength
private void removeSurplus() {
JFormattedTextField ftf = getFormattedTextField();
ftf.setText(ftf.getText().substring(0, mLength));
}
//Takes an object and creates a String-representation
public String valueToString(Object value) throws ParseException {
if (value != null && value.toString().length() >= mLength) {
invalidEdit();
return value.toString().substring(0, mLength);
}
else {
return super.valueToString(value);
}
}
void commitEdit() throws ParseException {
JFormattedTextField ftf = getFormattedTextField();
if (ftf != null && ftf.getText().length() < mLength) {
ftf.commitEdit();
}
}
protected DocumentFilter getDocumentFilter() {
if (mFilter == null) {
return super.getDocumentFilter();
}
else {
return mFilter;
}
}
public void setFilter(DocumentFilter pFilter) {
mFilter = pFilter;
}
}
class FormattedTextField extends JFormattedTextField {
private boolean mOverwriteMode = false;
private JFormattedTextField.AbstractFormatter mFormatter;
public FormattedTextField() {
}
public FormattedTextField(JFormattedTextField.AbstractFormatterFactory factory) {
super(factory);
}
public FormattedTextField(JFormattedTextField.AbstractFormatterFactory factory, Object currentValue) {
super(factory, currentValue);
}
public FormattedTextField(java.text.Format format) {
super(format);
}
public FormattedTextField(JFormattedTextField.AbstractFormatter formatter) {
super(formatter);
mFormatter = formatter;
}
public FormattedTextField(Object value) {
super(value);
}
public void toggleOverwriteMode() {
mOverwriteMode = !mOverwriteMode;
((DefaultFormatter) mFormatter).setOverwriteMode(mOverwriteMode);
System.out.println("Überschreibe-Modus= " + mOverwriteMode);
}
}
class LimitedLengthDocumentFilter extends DocumentFilter {
private final int mLimit;
private final JFormattedTextField mTextField;
public LimitedLengthDocumentFilter(int pLimit, JFormattedTextField pTextField) {
mLimit = pLimit;
mTextField = pTextField;
}
/**
* This method is always chosen because the documents used are derived from AbstractDocument
* and calls to setText on a JTextComponent then calls this method.
*/
public void replace(DocumentFilter.FilterBypass fb,
int offset,
int length,
String text,
AttributeSet attrs) throws BadLocationException {
if ((text != null) && (!"".equals(text))) {
//setting limit to -1 sets the field to umlimited.
if (mLimit == -1) {
super.replace(fb, offset, length, text, attrs);
}
else {
String lPreviousText = fb.getDocument().getText(0, fb.getDocument().getLength());
if (lPreviousText.concat(text).length() <= mLimit) {
super.replace(fb, offset, length, text, attrs);
}
else { //The resulting string would be longer than lLimit: truncate the string
if (mTextField.getSelectedText() == null) {
//No text selected -> paste as much text as possible and beep
if (lPreviousText.length() < mLimit) {
String lTruncatedText = text.substring(0, (mLimit - lPreviousText.length()));
super.replace(fb, offset, length, lTruncatedText, attrs);
}
Toolkit.getDefaultToolkit().beep();
}
//there was a selection:
else {
//If the result of the replacement of the selection still fits with the limit:
//do the replacement
if (fb.getDocument().getLength() + text.length() - mTextField.getSelectedText().length() <= mLimit) {
super.replace(fb, offset, length, text, attrs);
}
//The resulting contents would be too long:
else {
//Do the replacement, but truncate the new text to the lengh of the selection and beep.
String lTruncatedText = text.substring(0, mTextField.getSelectedText().length());
super.replace(fb, offset, length, lTruncatedText, attrs);
Toolkit.getDefaultToolkit().beep();
}
}
}
}
}
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Not found yet.
Documented in Release Notes.