JDK-4424708 : JPasswordField cursor placed incorrectly after setText("")
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.1.7,1.3.0
  • Priority: P4
  • Status: Closed
  • Resolution: Cannot Reproduce
  • OS: windows_nt,windows_2000
  • CPU: x86
  • Submitted: 2001-03-12
  • Updated: 2003-09-29
  • Resolved: 2003-09-29
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Description

Name: yyT116575			Date: 03/12/2001


C:\>java -version
java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)

The cursor for a password field does not seem to be correctly reset for a
when the field is cleared using setText(""). Please run the following code to
see this problem.

/**
* Simple class to demonstrate a problem (?) with JPasswordField.
* Problem detected on an NT machine running Java version:
*
*  C:\>java -version
*  java version "1.3.0"
*  Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
*  Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)
*
* The problem: The cursor does not seem to be correctly reset for a
* JPasswordField when the field is cleared using setText("")
*
* To replicate: Run this class. A dialog is shown 3 times. It prompts
* for a user-id and a password.
*
* When appears for the first time, enter any text (say 5 or 6 chars)
* at BOTH the user-id and password fields. Press the OK button.
*
* When the dialog appears for the SECOND time, enter some text at
* the user-id field and then TAB (ie: do NOT use the mouse) to the
* password field. Note that the cursor is NOT at the start of the
* field, but is still at the end of the previously entered text for
* the field, even through the text is no longer displayed!!
*
* The third display of the dialog is just an example of using the
* Caret of the JPasswordField to force it to display correctly when
* you TAB to the password field.
*
* This problem may (??) be related to bug 4139009
*/

import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;

public class TestPwdProblem extends JFrame {
  private JPanel TestPwdPanel;
  private JTextField idText;
  private JPasswordField pwdText;

  public static void main(String[] args) {
    int val;
    TestPwdProblem tpp = new TestPwdProblem();

    val = JOptionPane.showOptionDialog(tpp, tpp.getPanel(), null,
        JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE,
        null, null, null);

    tpp.resetThatFails(); // 'Clear' the user-id and password fields!

    val = JOptionPane.showOptionDialog(tpp, tpp.getPanel(), null,
        JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE,
        null, null, null);

    tpp.resetThatWorks();

    val = JOptionPane.showOptionDialog(tpp, tpp.getPanel(), null,
        JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE,
        null, null, null);
  }

  public TestPwdProblem() {
    TestPwdPanel = new JPanel();

    idText  = new JTextField(20);
    pwdText = new JPasswordField(20);

    JLabel idLabel = new JLabel("User id");
    JLabel pwdLabel = new JLabel("Password");

    GridBagLayout gbl = new GridBagLayout();
    GridBagConstraints gbc = new GridBagConstraints();

    TestPwdPanel.setLayout(gbl);

    gbc.fill = GridBagConstraints.NONE;
    gbc.anchor = GridBagConstraints.WEST;
    gbc.insets = new Insets(4, 4, 4, 10);
    gbl.setConstraints(idLabel, gbc);
    TestPwdPanel.add(idLabel);

    gbc.gridwidth = GridBagConstraints.REMAINDER;
    gbc.insets = new Insets(4, 0, 4, 4);
    gbl.setConstraints(idText, gbc);
    TestPwdPanel.add(idText);

    gbc.gridwidth = 1;
    gbc.insets = new Insets(0, 4, 4, 10);
    gbl.setConstraints(pwdLabel, gbc);
    TestPwdPanel.add(pwdLabel);

    gbc.gridwidth = GridBagConstraints.REMAINDER;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    gbc.insets = new Insets(0, 0, 4, 4);
    gbl.setConstraints(pwdText, gbc);
    TestPwdPanel.add(pwdText);
  }

  public JPanel getPanel() {
    return (TestPwdPanel);
  }

  public void resetThatFails() {
    idText.setText("");
    pwdText.setText("");
  }

  public void resetThatWorks() {
    idText.setText("");

    pwdText.setText("");
    Caret c = pwdText.getCaret();
    c.setDot(0);
  }
}
(Review ID: 118355) 
======================================================================

Comments
EVALUATION Name: apR10133 Date: 09/11/2001 The problem is that the DefaultCursor doesn't updates position on the main thread but do it on the EventDispatchThread. So, when the JTextComponent.setText() method is called on the main thread the DefaultCursor doesn't update its position. This bug is related to 4226384. ###@###.### ====================================================================== Name: slR10134 Date: 05/24/2002 (###@###.###) The reason of the bug is the following: when developer invokes method setText("") the JTextComponent invokes "doc.remove(0, doc.getLength());". It causes the raising of "removeUpdate" event. DefaultCaret is one of the listeners of this event. When DefaultCaret receives notification about "removeUpdate" event it invokes method "removeUpdate". The code of method "removeUpdate" can be executed only in event thread (there is checking of whether the current thread is the event one). So this code is not run in main thread (where setText is invoked) and hence position of cursor is not recalculated. The idea of suggested fix is to run the code of method "removeUpdate" in event thread by using of method "invokeLater" of Utilities. ====================================================================== I don't necessarily agree with the suggested fix. The caret doesn't respond to the update because the value of DefaultCaret.getAsynchronousMovement() is false. Investigation into the fix for this bug should include a determination of whether or not this property can be used. ###@###.### 2002-06-05 Name: anR10225 Date: 09/29/2003 The bug is not reproducible since the fix for 4201999 was integrated. Currently the caret correctly process removal from document at both the Event Dispatch Thread and other. ======================================================================
11-06-2004

SUGGESTED FIX Name: slR10134 Date: 05/24/2002 ------- DefaultCaret.java ------- *** /tmp/sccs.Hza4uk Fri May 24 18:09:59 2002 --- DefaultCaret.java Fri May 24 18:07:28 2002 *************** *** 1475,1481 **** --- 1475,1492 ---- * @see DocumentListener#removeUpdate */ public void removeUpdate(DocumentEvent e) { + final DocumentEvent event = e; if (async || SwingUtilities.isEventDispatchThread()) { + helpRemoveUpdate(e); + } else { + Runnable doWorkRunnable = new Runnable() { + public void run() { helpRemoveUpdate(event); } + }; + SwingUtilities.invokeLater(doWorkRunnable); + } + } + + void helpRemoveUpdate(DocumentEvent e) { int adjust = 0; int offs0 = e.getOffset(); int offs1 = offs0 + e.getLength(); *************** *** 1527,1533 **** } ensureValidPosition(); } - } } /** --- 1538,1543 ---- ======================================================================
11-06-2004