diff --git a/CHANGELOG.md b/CHANGELOG.md index d4c09ddc2..fada280e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ FlatLaf Change Log This gives FlatLaf windows a more "native" feeling. (issue #482) - MenuBar: Support different menu selection style UI defaults for `MenuBar` and `MenuItem`. (issue #587) +- PasswordField: Reveal button is now hidden (and turned off) if password field + is disabled. (issue #501) - TabbedPane: New option to disable tab run rotation in wrap layout. Set UI value `TabbedPane.rotateTabRuns` to `false`. (issue #574) - Native window decorations (Windows 10/11 only): Added client property to mark diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPasswordFieldUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPasswordFieldUI.java index 91536014d..d179890eb 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPasswordFieldUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPasswordFieldUI.java @@ -23,6 +23,7 @@ import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; +import java.beans.PropertyChangeEvent; import java.util.Map; import javax.swing.Action; import javax.swing.ActionMap; @@ -291,6 +292,7 @@ protected boolean isCapsLockVisible() { protected void installRevealButton() { if( showRevealButton ) { revealButton = createRevealButton(); + updateRevealButton(); installLayout(); getComponent().add( revealButton ); } @@ -298,28 +300,64 @@ protected void installRevealButton() { /** @since 2 */ protected JToggleButton createRevealButton() { - JToggleButton button = new JToggleButton( revealIcon ); + JPasswordField c = (JPasswordField) getComponent(); + JToggleButton button = new JToggleButton( revealIcon, !c.echoCharIsSet() ); button.setName( "PasswordField.revealButton" ); prepareLeadingOrTrailingComponent( button ); button.putClientProperty( FlatClientProperties.STYLE_CLASS, "inTextField revealButton" ); - if( FlatClientProperties.clientPropertyBoolean( getComponent(), KEY_REVEAL_SELECTED, false ) ) { + if( FlatClientProperties.clientPropertyBoolean( c, KEY_REVEAL_SELECTED, false ) ) { button.setSelected( true ); updateEchoChar( true ); } button.addActionListener( e -> { boolean selected = button.isSelected(); updateEchoChar( selected ); - getComponent().putClientProperty( KEY_REVEAL_SELECTED, selected ); + c.putClientProperty( KEY_REVEAL_SELECTED, selected ); } ); return button; } + /** @since 2.5 */ + protected void updateRevealButton() { + if( revealButton == null ) + return; + + JTextComponent c = getComponent(); + boolean visible = c.isEnabled(); + if( visible != revealButton.isVisible() ) { + revealButton.setVisible( visible ); + c.revalidate(); + c.repaint(); + + if( !visible ) { + revealButton.setSelected( false ); + updateEchoChar( false ); + getComponent().putClientProperty( KEY_REVEAL_SELECTED, null ); + } + } + } + + @Override + protected void propertyChange( PropertyChangeEvent e ) { + super.propertyChange( e ); + + switch( e.getPropertyName() ) { + case "enabled": + updateRevealButton(); + break; + } + } + private void updateEchoChar( boolean selected ) { char newEchoChar = selected ? 0 : (echoChar != null ? echoChar : '*'); JPasswordField c = (JPasswordField) getComponent(); + if( newEchoChar == c.getEchoChar() ) + return; + + // set echo char LookAndFeel.installProperty( c, "echoChar", newEchoChar ); // check whether was able to set echo char via LookAndFeel.installProperty() diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.java index a8fcd2492..b9dbeb409 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.java @@ -25,6 +25,7 @@ import javax.swing.*; import javax.swing.border.*; import javax.swing.text.DefaultEditorKit; +import javax.swing.text.JTextComponent; import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.util.UIScale; import net.miginfocom.swing.*; @@ -46,6 +47,14 @@ public static void main( String[] args ) { initComponents(); } + private void editableChanged() { + boolean editable = editableCheckBox.isSelected(); + for( Component c : getComponents() ) { + if( c instanceof JTextComponent ) + ((JTextComponent)c).setEditable( editable ); + } + } + private void changeText() { textField1.setText( "new text" ); } @@ -166,6 +175,7 @@ private void initComponents() { JFormattedTextField formattedTextField1 = new JFormattedTextField(); JFormattedTextField formattedTextField3 = new JFormattedTextField(); JPanel panel1 = new JPanel(); + editableCheckBox = new JCheckBox(); JButton button1 = new JButton(); JLabel leftPaddingLabel = new JLabel(); leftPaddingField = new JSpinner(); @@ -321,6 +331,7 @@ private void initComponents() { "[]" + "[]" + "[]" + + "[]" + "[]0" + "[]" + "[]0" + @@ -330,84 +341,90 @@ private void initComponents() { "[]" + "[]")); + //---- editableCheckBox ---- + editableCheckBox.setText("editable"); + editableCheckBox.setSelected(true); + editableCheckBox.addActionListener(e -> editableChanged()); + panel1.add(editableCheckBox, "cell 0 0 2 1,alignx left,growx 0"); + //---- button1 ---- button1.setText("change text"); button1.addActionListener(e -> changeText()); - panel1.add(button1, "cell 0 0 2 1,alignx left,growx 0"); + panel1.add(button1, "cell 0 1 2 1,alignx left,growx 0"); //---- leftPaddingLabel ---- leftPaddingLabel.setText("Left padding:"); - panel1.add(leftPaddingLabel, "cell 0 1"); + panel1.add(leftPaddingLabel, "cell 0 2"); //---- leftPaddingField ---- leftPaddingField.addChangeListener(e -> paddingChanged()); - panel1.add(leftPaddingField, "cell 1 1"); + panel1.add(leftPaddingField, "cell 1 2"); //---- rightPaddingLabel ---- rightPaddingLabel.setText("Right padding:"); - panel1.add(rightPaddingLabel, "cell 0 2"); + panel1.add(rightPaddingLabel, "cell 0 3"); //---- rightPaddingField ---- rightPaddingField.addChangeListener(e -> paddingChanged()); - panel1.add(rightPaddingField, "cell 1 2"); + panel1.add(rightPaddingField, "cell 1 3"); //---- topPaddingLabel ---- topPaddingLabel.setText("Top padding:"); - panel1.add(topPaddingLabel, "cell 0 3"); + panel1.add(topPaddingLabel, "cell 0 4"); //---- topPaddingField ---- topPaddingField.addChangeListener(e -> paddingChanged()); - panel1.add(topPaddingField, "cell 1 3"); + panel1.add(topPaddingField, "cell 1 4"); //---- bottomPaddingLabel ---- bottomPaddingLabel.setText("Bottom padding:"); - panel1.add(bottomPaddingLabel, "cell 0 4"); + panel1.add(bottomPaddingLabel, "cell 0 5"); //---- bottomPaddingField ---- bottomPaddingField.addChangeListener(e -> paddingChanged()); - panel1.add(bottomPaddingField, "cell 1 4"); + panel1.add(bottomPaddingField, "cell 1 5"); //---- leadingIconCheckBox ---- leadingIconCheckBox.setText("leading icon"); leadingIconCheckBox.addActionListener(e -> leadingIcon()); - panel1.add(leadingIconCheckBox, "cell 0 5 2 1,alignx left,growx 0"); + panel1.add(leadingIconCheckBox, "cell 0 6 2 1,alignx left,growx 0"); //---- trailingIconCheckBox ---- trailingIconCheckBox.setText("trailing icon"); trailingIconCheckBox.addActionListener(e -> trailingIcon()); - panel1.add(trailingIconCheckBox, "cell 0 6 2 1,alignx left,growx 0"); + panel1.add(trailingIconCheckBox, "cell 0 7 2 1,alignx left,growx 0"); //---- leadingComponentCheckBox ---- leadingComponentCheckBox.setText("leading component"); leadingComponentCheckBox.addActionListener(e -> leadingComponent()); - panel1.add(leadingComponentCheckBox, "cell 0 7 2 1,alignx left,growx 0"); + panel1.add(leadingComponentCheckBox, "cell 0 8 2 1,alignx left,growx 0"); //---- trailingComponentCheckBox ---- trailingComponentCheckBox.setText("trailing component"); trailingComponentCheckBox.addActionListener(e -> trailingComponent()); - panel1.add(trailingComponentCheckBox, "cell 0 8 2 1,alignx left,growx 0"); + panel1.add(trailingComponentCheckBox, "cell 0 9 2 1,alignx left,growx 0"); //---- leadingComponentVisibleCheckBox ---- leadingComponentVisibleCheckBox.setText("leading component visible"); leadingComponentVisibleCheckBox.setSelected(true); leadingComponentVisibleCheckBox.addActionListener(e -> leadingComponentVisible()); - panel1.add(leadingComponentVisibleCheckBox, "cell 0 9 2 1,alignx left,growx 0"); + panel1.add(leadingComponentVisibleCheckBox, "cell 0 10 2 1,alignx left,growx 0"); //---- trailingComponentVisibleCheckBox ---- trailingComponentVisibleCheckBox.setText("trailing component visible"); trailingComponentVisibleCheckBox.setSelected(true); trailingComponentVisibleCheckBox.addActionListener(e -> trailingComponentVisible()); - panel1.add(trailingComponentVisibleCheckBox, "cell 0 10 2 1,alignx left,growx 0"); + panel1.add(trailingComponentVisibleCheckBox, "cell 0 11 2 1,alignx left,growx 0"); //---- showClearButtonCheckBox ---- showClearButtonCheckBox.setText("clear button"); showClearButtonCheckBox.addActionListener(e -> showClearButton()); - panel1.add(showClearButtonCheckBox, "cell 0 11 2 1,alignx left,growx 0"); + panel1.add(showClearButtonCheckBox, "cell 0 12 2 1,alignx left,growx 0"); //---- showRevealButtonCheckBox ---- showRevealButtonCheckBox.setText("password reveal button"); showRevealButtonCheckBox.addActionListener(e -> showRevealButton()); - panel1.add(showRevealButtonCheckBox, "cell 0 12 2 1,alignx left,growx 0"); + panel1.add(showRevealButtonCheckBox, "cell 0 13 2 1,alignx left,growx 0"); } add(panel1, "cell 4 0 1 10,aligny top,growy 0"); @@ -660,6 +677,7 @@ private void initComponents() { // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables private JTextField textField1; + private JCheckBox editableCheckBox; private JSpinner leftPaddingField; private JSpinner rightPaddingField; private JSpinner topPaddingField; diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.jfd index 316a828fa..41e11bf18 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.jfd +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.jfd @@ -76,23 +76,34 @@ new FormModel { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "hidemode 3" "$columnConstraints": "[fill][fill]" - "$rowConstraints": "[][][][][][]0[][]0[][]0[][][]" + "$rowConstraints": "[][][][][][][]0[][]0[][]0[][][]" } ) { name: "panel1" "border": new javax.swing.border.TitledBorder( "Control" ) "$client.FlatLaf.internal.testing.ignore": true + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "editableCheckBox" + "text": "editable" + "selected": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "editableChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 0 2 1,alignx left,growx 0" + } ) add( new FormComponent( "javax.swing.JButton" ) { name: "button1" "text": "change text" addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "changeText", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 0 2 1,alignx left,growx 0" + "value": "cell 0 1 2 1,alignx left,growx 0" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "leftPaddingLabel" "text": "Left padding:" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 1" + "value": "cell 0 2" } ) add( new FormComponent( "javax.swing.JSpinner" ) { name: "leftPaddingField" @@ -101,13 +112,13 @@ new FormModel { } addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "paddingChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 1" + "value": "cell 1 2" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "rightPaddingLabel" "text": "Right padding:" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 2" + "value": "cell 0 3" } ) add( new FormComponent( "javax.swing.JSpinner" ) { name: "rightPaddingField" @@ -116,13 +127,13 @@ new FormModel { } addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "paddingChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 2" + "value": "cell 1 3" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "topPaddingLabel" "text": "Top padding:" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 3" + "value": "cell 0 4" } ) add( new FormComponent( "javax.swing.JSpinner" ) { name: "topPaddingField" @@ -131,13 +142,13 @@ new FormModel { } addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "paddingChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 3" + "value": "cell 1 4" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "bottomPaddingLabel" "text": "Bottom padding:" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 4" + "value": "cell 0 5" } ) add( new FormComponent( "javax.swing.JSpinner" ) { name: "bottomPaddingField" @@ -146,7 +157,7 @@ new FormModel { } addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "paddingChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 4" + "value": "cell 1 5" } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "leadingIconCheckBox" @@ -156,7 +167,7 @@ new FormModel { } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "leadingIcon", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 5 2 1,alignx left,growx 0" + "value": "cell 0 6 2 1,alignx left,growx 0" } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "trailingIconCheckBox" @@ -166,7 +177,7 @@ new FormModel { } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "trailingIcon", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 6 2 1,alignx left,growx 0" + "value": "cell 0 7 2 1,alignx left,growx 0" } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "leadingComponentCheckBox" @@ -176,7 +187,7 @@ new FormModel { } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "leadingComponent", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 7 2 1,alignx left,growx 0" + "value": "cell 0 8 2 1,alignx left,growx 0" } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "trailingComponentCheckBox" @@ -186,7 +197,7 @@ new FormModel { } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "trailingComponent", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 8 2 1,alignx left,growx 0" + "value": "cell 0 9 2 1,alignx left,growx 0" } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "leadingComponentVisibleCheckBox" @@ -197,7 +208,7 @@ new FormModel { } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "leadingComponentVisible", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 9 2 1,alignx left,growx 0" + "value": "cell 0 10 2 1,alignx left,growx 0" } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "trailingComponentVisibleCheckBox" @@ -208,7 +219,7 @@ new FormModel { } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "trailingComponentVisible", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 10 2 1,alignx left,growx 0" + "value": "cell 0 11 2 1,alignx left,growx 0" } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "showClearButtonCheckBox" @@ -218,7 +229,7 @@ new FormModel { } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showClearButton", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 11 2 1,alignx left,growx 0" + "value": "cell 0 12 2 1,alignx left,growx 0" } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "showRevealButtonCheckBox" @@ -228,7 +239,7 @@ new FormModel { } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showRevealButton", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 12 2 1,alignx left,growx 0" + "value": "cell 0 13 2 1,alignx left,growx 0" } ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 4 0 1 10,aligny top,growy 0"