Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6359489

Overwrite mode cannot be changed in DefaultFormatter when DocumentFilter is set

XMLWordPrintable

      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.

            svioletsunw Scott Violet (Inactive)
            jssunw Jitender S (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: