From 48bdd5c3dfcae394f8a9a5208843c833f186e9fe Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sun, 19 Jan 2020 18:05:12 +0100 Subject: [PATCH] TextField, FormattedTextField and PasswordField: select all text when a text field gains focus for the first time and selection was not set explicitly --- CHANGELOG.md | 8 + .../formdev/flatlaf/FlatClientProperties.java | 36 +- .../com/formdev/flatlaf/ui/FlatCaret.java | 128 +++++++ .../flatlaf/ui/FlatFormattedTextFieldUI.java | 1 + .../flatlaf/ui/FlatPasswordFieldUI.java | 7 + .../formdev/flatlaf/ui/FlatTextFieldUI.java | 7 + .../com/formdev/flatlaf/FlatLaf.properties | 6 + .../flatlaf/demo/BasicComponentsPanel.java | 35 ++ .../flatlaf/demo/BasicComponentsPanel.jfd | 30 +- .../com/formdev/flatlaf/demo/DemoFrame.java | 8 +- .../com/formdev/flatlaf/demo/DemoFrame.jfd | 3 - .../testing/FlatTextComponentsTest.java | 339 ++++++++++++++++++ .../testing/FlatTextComponentsTest.jfd | 259 +++++++++++++ 13 files changed, 859 insertions(+), 8 deletions(-) create mode 100644 flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCaret.java create mode 100644 flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.java create mode 100644 flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.jfd diff --git a/CHANGELOG.md b/CHANGELOG.md index dd42c9df..b48ca658 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ FlatLaf Change Log ================== +## Unreleased + +- TextField, FormattedTextField and PasswordField: Select all text when a text + field gains focus for the first time and selection was not set explicitly. + This can be configured to newer or always select all text on focus gain (see + UI default value `TextComponent.selectAllOnFocusPolicy`). + + ## 0.25.1 Re-release of 0.25 because of problems with Maven Central. diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java index 98ca89c2..33065d19 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java @@ -141,10 +141,44 @@ public interface FlatClientProperties */ String TABBED_PANE_TAB_HEIGHT = "JTabbedPane.tabHeight"; + /** + * Specifies whether all text is selected when the text component gains focus. + *

+ * Component {@link javax.swing.JTextField} (and subclasses)
+ * Value type {@link java.lang.String}
+ * Allowed Values {@link #SELECT_ALL_ON_FOCUS_POLICY_NEVER}, + * {@link #SELECT_ALL_ON_FOCUS_POLICY_ONCE} (default) or + * {@link #SELECT_ALL_ON_FOCUS_POLICY_ALWAYS} + */ + String SELECT_ALL_ON_FOCUS_POLICY = "JTextField.selectAllOnFocusPolicy"; + + /** + * Never select all text when the text component gains focus. + * + * @see #SELECT_ALL_ON_FOCUS_POLICY + */ + String SELECT_ALL_ON_FOCUS_POLICY_NEVER = "never"; + + /** + * Select all text when the text component gains focus for the first time + * and selection was not modified (is at end of text). + * This is the default. + * + * @see #SELECT_ALL_ON_FOCUS_POLICY + */ + String SELECT_ALL_ON_FOCUS_POLICY_ONCE = "once"; + + /** + * Always select all text when the text component gains focus. + * + * @see #SELECT_ALL_ON_FOCUS_POLICY + */ + String SELECT_ALL_ON_FOCUS_POLICY_ALWAYS = "always"; + /** * Placeholder text that is only painted if the text field is empty. *

- * Component {@link javax.swing.JTextField} or {@link javax.swing.JComboBox}
+ * Component {@link javax.swing.JTextField} (and subclasses) or {@link javax.swing.JComboBox}
* Value type {@link java.lang.String} */ String PLACEHOLDER_TEXT = "JTextField.placeholderText"; diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCaret.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCaret.java new file mode 100644 index 00000000..5704135c --- /dev/null +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCaret.java @@ -0,0 +1,128 @@ +/* + * Copyright 2020 FormDev Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.formdev.flatlaf.ui; + +import static com.formdev.flatlaf.FlatClientProperties.*; +import java.awt.EventQueue; +import java.awt.event.FocusEvent; +import java.awt.event.MouseEvent; +import javax.swing.JFormattedTextField; +import javax.swing.plaf.UIResource; +import javax.swing.text.DefaultCaret; +import javax.swing.text.Document; +import javax.swing.text.JTextComponent; + +/** + * Caret that can select all text on focus gained. + * + * @author Karl Tauber + */ +class FlatCaret + extends DefaultCaret + implements UIResource +{ + private final String selectAllOnFocusPolicy; + + private boolean wasFocused; + private boolean wasTemporaryLost; + private boolean isMousePressed; + + FlatCaret( String selectAllOnFocusPolicy ) { + this.selectAllOnFocusPolicy = selectAllOnFocusPolicy; + } + + @Override + public void install( JTextComponent c ) { + super.install( c ); + + // the dot and mark are lost when switching LaF + // --> move dot to end of text so that all text may be selected when it gains focus + Document doc = c.getDocument(); + if( doc != null && getDot() == 0 && getMark() == 0 ) { + int length = doc.getLength(); + if( length > 0 ) + setDot( length ); + } + } + + @Override + public void focusGained( FocusEvent e ) { + if( !wasTemporaryLost && !isMousePressed ) + selectAllOnFocusGained(); + wasTemporaryLost = false; + wasFocused = true; + + super.focusGained( e ); + } + + @Override + public void focusLost( FocusEvent e ) { + wasTemporaryLost = e.isTemporary(); + super.focusLost( e ); + } + + @Override + public void mousePressed( MouseEvent e ) { + isMousePressed = true; + super.mousePressed( e ); + } + + @Override + public void mouseReleased( MouseEvent e ) { + isMousePressed = false; + super.mouseReleased( e ); + } + + private void selectAllOnFocusGained() { + JTextComponent c = getComponent(); + Document doc = c.getDocument(); + if( doc == null || !c.isEnabled() || !c.isEditable() ) + return; + + Object selectAllOnFocusPolicy = c.getClientProperty( SELECT_ALL_ON_FOCUS_POLICY ); + if( selectAllOnFocusPolicy == null ) + selectAllOnFocusPolicy = this.selectAllOnFocusPolicy; + + if( SELECT_ALL_ON_FOCUS_POLICY_NEVER.equals( selectAllOnFocusPolicy ) ) + return; + + if( !SELECT_ALL_ON_FOCUS_POLICY_ALWAYS.equals( selectAllOnFocusPolicy ) ) { + // policy is "once" (or null or unknown) + + // was already focused? + if( wasFocused ) + return; + + // check whether selection was modified before gaining focus + int dot = getDot(); + int mark = getMark(); + if( dot != mark || dot != doc.getLength() ) + return; + } + + // select all + if( c instanceof JFormattedTextField ) { + EventQueue.invokeLater( () -> { + setDot( 0 ); + moveDot( doc.getLength() ); + } ); + } else { + setDot( 0 ); + moveDot( doc.getLength() ); + } + } +} diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatFormattedTextFieldUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatFormattedTextFieldUI.java index 3bbcbbc6..8322ba64 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatFormattedTextFieldUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatFormattedTextFieldUI.java @@ -43,6 +43,7 @@ import javax.swing.plaf.ComponentUI; * @uiDefault Component.minimumWidth int * @uiDefault Component.isIntelliJTheme boolean * @uiDefault FormattedTextField.placeholderForeground Color + * @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always * * @author Karl Tauber */ 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 40fe9586..d915aec1 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 @@ -27,6 +27,7 @@ import javax.swing.LookAndFeel; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicPasswordFieldUI; +import javax.swing.text.Caret; import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.util.SystemInfo; @@ -55,6 +56,7 @@ import com.formdev.flatlaf.util.SystemInfo; * @uiDefault Component.minimumWidth int * @uiDefault Component.isIntelliJTheme boolean * @uiDefault PasswordField.placeholderForeground Color + * @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always * * @author Karl Tauber */ @@ -116,6 +118,11 @@ public class FlatPasswordFieldUI focusListener = null; } + @Override + protected Caret createCaret() { + return new FlatCaret( UIManager.getString( "TextComponent.selectAllOnFocusPolicy" ) ); + } + @Override protected void propertyChange( PropertyChangeEvent e ) { super.propertyChange( e ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java index 47f97005..35deedbb 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java @@ -35,6 +35,7 @@ import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicTextFieldUI; +import javax.swing.text.Caret; import javax.swing.text.JTextComponent; import com.formdev.flatlaf.FlatClientProperties; @@ -62,6 +63,7 @@ import com.formdev.flatlaf.FlatClientProperties; * @uiDefault Component.minimumWidth int * @uiDefault Component.isIntelliJTheme boolean * @uiDefault TextField.placeholderForeground Color + * @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always * * @author Karl Tauber */ @@ -119,6 +121,11 @@ public class FlatTextFieldUI focusListener = null; } + @Override + protected Caret createCaret() { + return new FlatCaret( UIManager.getString( "TextComponent.selectAllOnFocusPolicy" ) ); + } + @Override protected void propertyChange( PropertyChangeEvent e ) { super.propertyChange( e ); diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties index e7505ba1..e1ea0c5b 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties @@ -407,6 +407,12 @@ TextArea.margin=@textComponentMargin TextArea.background=@textComponentBackground +#---- TextComponent ---- + +# allowed values: "never", "once" (default) or "always" +TextComponent.selectAllOnFocusPolicy=once + + #---- TextField ---- TextField.border=com.formdev.flatlaf.ui.FlatBorder diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/BasicComponentsPanel.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/BasicComponentsPanel.java index b7ca8714..2e73567c 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/BasicComponentsPanel.java +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/BasicComponentsPanel.java @@ -17,6 +17,7 @@ package com.formdev.flatlaf.demo; import javax.swing.*; +import javax.swing.text.DefaultEditorKit; import net.miginfocom.swing.*; /** @@ -113,6 +114,10 @@ class BasicComponentsPanel JScrollPane scrollPane12 = new JScrollPane(); JTextPane textPane4 = new JTextPane(); JTextPane textPane5 = new JTextPane(); + JPopupMenu popupMenu1 = new JPopupMenu(); + JMenuItem cutMenuItem = new JMenuItem(); + JMenuItem copyMenuItem = new JMenuItem(); + JMenuItem pasteMenuItem = new JMenuItem(); //======== this ======== setLayout(new MigLayout( @@ -260,6 +265,8 @@ class BasicComponentsPanel //---- comboBoxLabel ---- comboBoxLabel.setText("JComboBox:"); + comboBoxLabel.setDisplayedMnemonic('C'); + comboBoxLabel.setLabelFor(comboBox1); add(comboBoxLabel, "cell 0 4"); //---- comboBox1 ---- @@ -314,6 +321,8 @@ class BasicComponentsPanel //---- spinnerLabel ---- spinnerLabel.setText("JSpinner:"); + spinnerLabel.setLabelFor(spinner1); + spinnerLabel.setDisplayedMnemonic('S'); add(spinnerLabel, "cell 0 5"); add(spinner1, "cell 1 5,growx"); @@ -328,10 +337,13 @@ class BasicComponentsPanel //---- textFieldLabel ---- textFieldLabel.setText("JTextField:"); + textFieldLabel.setDisplayedMnemonic('T'); + textFieldLabel.setLabelFor(textField1); add(textFieldLabel, "cell 0 6"); //---- textField1 ---- textField1.setText("editable"); + textField1.setComponentPopupMenu(popupMenu1); add(textField1, "cell 1 6,growx"); //---- textField2 ---- @@ -356,10 +368,13 @@ class BasicComponentsPanel //---- formattedTextFieldLabel ---- formattedTextFieldLabel.setText("JFormattedTextField:"); + formattedTextFieldLabel.setLabelFor(formattedTextField1); + formattedTextFieldLabel.setDisplayedMnemonic('O'); add(formattedTextFieldLabel, "cell 0 7"); //---- formattedTextField1 ---- formattedTextField1.setText("editable"); + formattedTextField1.setComponentPopupMenu(popupMenu1); add(formattedTextField1, "cell 1 7,growx"); //---- formattedTextField2 ---- @@ -582,7 +597,27 @@ class BasicComponentsPanel //---- textPane5 ---- textPane5.setText("no scroll pane"); add(textPane5, "cell 5 11,growx"); + + //======== popupMenu1 ======== + { + + //---- cutMenuItem ---- + cutMenuItem.setText("Cut"); + popupMenu1.add(cutMenuItem); + + //---- copyMenuItem ---- + copyMenuItem.setText("Copy"); + popupMenu1.add(copyMenuItem); + + //---- pasteMenuItem ---- + pasteMenuItem.setText("Paste"); + popupMenu1.add(pasteMenuItem); + } // JFormDesigner - End of component initialization //GEN-END:initComponents + + cutMenuItem.addActionListener( new DefaultEditorKit.CutAction() ); + copyMenuItem.addActionListener( new DefaultEditorKit.CopyAction() ); + pasteMenuItem.addActionListener( new DefaultEditorKit.PasteAction() ); } // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/BasicComponentsPanel.jfd b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/BasicComponentsPanel.jfd index 469a8884..81c6bb83 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/BasicComponentsPanel.jfd +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/BasicComponentsPanel.jfd @@ -183,6 +183,8 @@ new FormModel { add( new FormComponent( "javax.swing.JLabel" ) { name: "comboBoxLabel" "text": "JComboBox:" + "displayedMnemonic": 67 + "labelFor": new FormReference( "comboBox1" ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 0 4" } ) @@ -254,6 +256,8 @@ new FormModel { add( new FormComponent( "javax.swing.JLabel" ) { name: "spinnerLabel" "text": "JSpinner:" + "labelFor": new FormReference( "spinner1" ) + "displayedMnemonic": 83 }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 0 5" } ) @@ -281,12 +285,15 @@ new FormModel { add( new FormComponent( "javax.swing.JLabel" ) { name: "textFieldLabel" "text": "JTextField:" + "displayedMnemonic": 84 + "labelFor": new FormReference( "textField1" ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 0 6" } ) add( new FormComponent( "javax.swing.JTextField" ) { name: "textField1" "text": "editable" + "componentPopupMenu": &FormReference0 new FormReference( "popupMenu1" ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 1 6,growx" } ) @@ -321,12 +328,15 @@ new FormModel { add( new FormComponent( "javax.swing.JLabel" ) { name: "formattedTextFieldLabel" "text": "JFormattedTextField:" + "labelFor": new FormReference( "formattedTextField1" ) + "displayedMnemonic": 79 }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 0 7" } ) add( new FormComponent( "javax.swing.JFormattedTextField" ) { name: "formattedTextField1" "text": "editable" + "componentPopupMenu": #FormReference0 }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 1 7,growx" } ) @@ -585,7 +595,25 @@ new FormModel { } ) }, new FormLayoutConstraints( null ) { "location": new java.awt.Point( 0, 0 ) - "size": new java.awt.Dimension( 790, 715 ) + "size": new java.awt.Dimension( 790, 440 ) + } ) + add( new FormContainer( "javax.swing.JPopupMenu", new FormLayoutManager( class javax.swing.JPopupMenu ) ) { + name: "popupMenu1" + add( new FormComponent( "javax.swing.JMenuItem" ) { + name: "cutMenuItem" + "text": "Cut" + } ) + add( new FormComponent( "javax.swing.JMenuItem" ) { + name: "copyMenuItem" + "text": "Copy" + } ) + add( new FormComponent( "javax.swing.JMenuItem" ) { + name: "pasteMenuItem" + "text": "Paste" + } ) + }, new FormLayoutConstraints( null ) { + "location": new java.awt.Point( 0, 500 ) + "size": new java.awt.Dimension( 91, 87 ) } ) } } diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java index 9a7c5208..3b365b21 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java @@ -19,6 +19,7 @@ package com.formdev.flatlaf.demo; import java.awt.*; import java.awt.event.*; import javax.swing.*; +import javax.swing.text.DefaultEditorKit; import com.formdev.flatlaf.demo.intellijthemes.*; import com.formdev.flatlaf.extras.FlatSVGIcon; import net.miginfocom.swing.*; @@ -175,21 +176,18 @@ class DemoFrame cutMenuItem.setText("Cut"); cutMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); cutMenuItem.setMnemonic('C'); - cutMenuItem.addActionListener(e -> menuItemActionPerformed(e)); editMenu.add(cutMenuItem); //---- copyMenuItem ---- copyMenuItem.setText("Copy"); copyMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); copyMenuItem.setMnemonic('O'); - copyMenuItem.addActionListener(e -> menuItemActionPerformed(e)); editMenu.add(copyMenuItem); //---- pasteMenuItem ---- pasteMenuItem.setText("Paste"); pasteMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); pasteMenuItem.setMnemonic('P'); - pasteMenuItem.addActionListener(e -> menuItemActionPerformed(e)); editMenu.add(pasteMenuItem); editMenu.addSeparator(); @@ -385,6 +383,10 @@ class DemoFrame pasteButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/menu-paste.svg" ) ); refreshButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/refresh.svg" ) ); showToggleButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/show.svg" ) ); + + cutMenuItem.addActionListener( new DefaultEditorKit.CutAction() ); + copyMenuItem.addActionListener( new DefaultEditorKit.CopyAction() ); + pasteMenuItem.addActionListener( new DefaultEditorKit.PasteAction() ); } // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd index 4912b254..179c618a 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd @@ -179,21 +179,18 @@ new FormModel { "text": "Cut" "accelerator": static javax.swing.KeyStroke getKeyStroke( 88, 4226, false ) "mnemonic": 67 - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "menuItemActionPerformed", true ) ) } ) add( new FormComponent( "javax.swing.JMenuItem" ) { name: "copyMenuItem" "text": "Copy" "accelerator": static javax.swing.KeyStroke getKeyStroke( 67, 4226, false ) "mnemonic": 79 - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "menuItemActionPerformed", true ) ) } ) add( new FormComponent( "javax.swing.JMenuItem" ) { name: "pasteMenuItem" "text": "Paste" "accelerator": static javax.swing.KeyStroke getKeyStroke( 86, 4226, false ) "mnemonic": 80 - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "menuItemActionPerformed", true ) ) } ) add( new FormComponent( "javax.swing.JPopupMenu$Separator" ) { name: "separator3" 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 new file mode 100644 index 00000000..06f722cd --- /dev/null +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.java @@ -0,0 +1,339 @@ +/* + * Copyright 2020 FormDev Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.formdev.flatlaf.testing; + +import javax.swing.*; +import javax.swing.text.DefaultEditorKit; +import net.miginfocom.swing.*; + +/** + * @author Karl Tauber + */ +public class FlatTextComponentsTest + extends FlatTestPanel +{ + public static void main( String[] args ) { + SwingUtilities.invokeLater( () -> { + FlatTestFrame frame = FlatTestFrame.create( args, "FlatTextComponentsTest" ); + frame.showFrame( FlatTextComponentsTest::new ); + } ); + } + + FlatTextComponentsTest() { + initComponents(); + } + + private void changeText() { + textField1.setText( "new text" ); + } + + private void initComponents() { + // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents + JLabel textFieldLabel = new JLabel(); + textField1 = new JTextField(); + JTextField textField3 = new JTextField(); + JTextField textField2 = new JTextField(); + JButton button1 = new JButton(); + JLabel formattedTextFieldLabel = new JLabel(); + JFormattedTextField formattedTextField1 = new JFormattedTextField(); + JFormattedTextField formattedTextField3 = new JFormattedTextField(); + JLabel passwordFieldLabel = new JLabel(); + JPasswordField passwordField1 = new JPasswordField(); + JPasswordField passwordField3 = new JPasswordField(); + JLabel textAreaLabel = new JLabel(); + JScrollPane scrollPane1 = new JScrollPane(); + JTextArea textArea1 = new JTextArea(); + JScrollPane scrollPane3 = new JScrollPane(); + JTextArea textArea3 = new JTextArea(); + JLabel editorPaneLabel = new JLabel(); + JScrollPane scrollPane5 = new JScrollPane(); + JEditorPane editorPane1 = new JEditorPane(); + JScrollPane scrollPane7 = new JScrollPane(); + JEditorPane editorPane3 = new JEditorPane(); + JLabel textPaneLabel = new JLabel(); + JScrollPane scrollPane9 = new JScrollPane(); + JTextPane textPane1 = new JTextPane(); + JScrollPane scrollPane11 = new JScrollPane(); + JTextPane textPane3 = new JTextPane(); + JLabel comboBoxLabel = new JLabel(); + JComboBox comboBox1 = new JComboBox<>(); + JComboBox comboBox3 = new JComboBox<>(); + JLabel spinnerLabel = new JLabel(); + JSpinner spinner1 = new JSpinner(); + JPopupMenu popupMenu1 = new JPopupMenu(); + JMenuItem cutMenuItem = new JMenuItem(); + JMenuItem copyMenuItem = new JMenuItem(); + JMenuItem pasteMenuItem = new JMenuItem(); + + //======== this ======== + setName("this"); + setLayout(new MigLayout( + "ltr,insets dialog,hidemode 3", + // columns + "[]" + + "[]" + + "[::100]" + + "[100,fill]" + + "[fill]", + // rows + "[]" + + "[]" + + "[]" + + "[50,fill]" + + "[50,fill]" + + "[50,fill]" + + "[]" + + "[]")); + + //---- textFieldLabel ---- + textFieldLabel.setText("JTextField:"); + textFieldLabel.setDisplayedMnemonic('T'); + textFieldLabel.setLabelFor(textField1); + textFieldLabel.setName("textFieldLabel"); + add(textFieldLabel, "cell 0 0"); + + //---- textField1 ---- + textField1.setText("editable"); + textField1.setComponentPopupMenu(popupMenu1); + textField1.setName("textField1"); + add(textField1, "cell 1 0,growx"); + + //---- textField3 ---- + textField3.setText("longer text for testing horizontal scrolling"); + textField3.setComponentPopupMenu(popupMenu1); + textField3.setName("textField3"); + add(textField3, "cell 2 0,growx"); + + //---- textField2 ---- + textField2.setText("partly selected"); + textField2.setSelectionStart(1); + textField2.setSelectionEnd(4); + textField2.setComponentPopupMenu(popupMenu1); + textField2.setName("textField2"); + add(textField2, "cell 3 0"); + + //---- button1 ---- + button1.setText("change text"); + button1.setName("button1"); + button1.addActionListener(e -> changeText()); + add(button1, "cell 4 0"); + + //---- formattedTextFieldLabel ---- + formattedTextFieldLabel.setText("JFormattedTextField:"); + formattedTextFieldLabel.setDisplayedMnemonic('F'); + formattedTextFieldLabel.setLabelFor(formattedTextField1); + formattedTextFieldLabel.setName("formattedTextFieldLabel"); + add(formattedTextFieldLabel, "cell 0 1"); + + //---- formattedTextField1 ---- + formattedTextField1.setText("editable"); + formattedTextField1.setComponentPopupMenu(popupMenu1); + formattedTextField1.setName("formattedTextField1"); + add(formattedTextField1, "cell 1 1,growx"); + + //---- formattedTextField3 ---- + formattedTextField3.setText("longer text for testing horizontal scrolling"); + formattedTextField3.setComponentPopupMenu(popupMenu1); + formattedTextField3.setName("formattedTextField3"); + add(formattedTextField3, "cell 2 1,growx"); + + //---- passwordFieldLabel ---- + passwordFieldLabel.setText("JPasswordField:"); + passwordFieldLabel.setDisplayedMnemonic('P'); + passwordFieldLabel.setLabelFor(passwordField1); + passwordFieldLabel.setName("passwordFieldLabel"); + add(passwordFieldLabel, "cell 0 2"); + + //---- passwordField1 ---- + passwordField1.setText("editable"); + passwordField1.setComponentPopupMenu(popupMenu1); + passwordField1.setName("passwordField1"); + add(passwordField1, "cell 1 2,growx"); + + //---- passwordField3 ---- + passwordField3.setText("longer text for testing horizontal scrolling"); + passwordField3.setComponentPopupMenu(popupMenu1); + passwordField3.setName("passwordField3"); + add(passwordField3, "cell 2 2,growx"); + + //---- textAreaLabel ---- + textAreaLabel.setText("JTextArea:"); + textAreaLabel.setDisplayedMnemonic('A'); + textAreaLabel.setLabelFor(textArea1); + textAreaLabel.setName("textAreaLabel"); + add(textAreaLabel, "cell 0 3"); + + //======== scrollPane1 ======== + { + scrollPane1.setName("scrollPane1"); + + //---- textArea1 ---- + textArea1.setText("editable"); + textArea1.setComponentPopupMenu(popupMenu1); + textArea1.setName("textArea1"); + scrollPane1.setViewportView(textArea1); + } + add(scrollPane1, "cell 1 3,growx"); + + //======== scrollPane3 ======== + { + scrollPane3.setName("scrollPane3"); + + //---- textArea3 ---- + textArea3.setText("longer text for testing horizontal scrolling"); + textArea3.setComponentPopupMenu(popupMenu1); + textArea3.setName("textArea3"); + scrollPane3.setViewportView(textArea3); + } + add(scrollPane3, "cell 2 3,growx"); + + //---- editorPaneLabel ---- + editorPaneLabel.setText("JEditorPane"); + editorPaneLabel.setDisplayedMnemonic('J'); + editorPaneLabel.setLabelFor(editorPane1); + editorPaneLabel.setName("editorPaneLabel"); + add(editorPaneLabel, "cell 0 4"); + + //======== scrollPane5 ======== + { + scrollPane5.setName("scrollPane5"); + + //---- editorPane1 ---- + editorPane1.setText("editable"); + editorPane1.setComponentPopupMenu(popupMenu1); + editorPane1.setName("editorPane1"); + scrollPane5.setViewportView(editorPane1); + } + add(scrollPane5, "cell 1 4,growx"); + + //======== scrollPane7 ======== + { + scrollPane7.setName("scrollPane7"); + + //---- editorPane3 ---- + editorPane3.setText("longer text for testing horizontal scrolling"); + editorPane3.setComponentPopupMenu(popupMenu1); + editorPane3.setName("editorPane3"); + scrollPane7.setViewportView(editorPane3); + } + add(scrollPane7, "cell 2 4,growx"); + + //---- textPaneLabel ---- + textPaneLabel.setText("JTextPane:"); + textPaneLabel.setDisplayedMnemonic('N'); + textPaneLabel.setLabelFor(textPane1); + textPaneLabel.setName("textPaneLabel"); + add(textPaneLabel, "cell 0 5"); + + //======== scrollPane9 ======== + { + scrollPane9.setName("scrollPane9"); + + //---- textPane1 ---- + textPane1.setText("editable"); + textPane1.setComponentPopupMenu(popupMenu1); + textPane1.setName("textPane1"); + scrollPane9.setViewportView(textPane1); + } + add(scrollPane9, "cell 1 5,growx"); + + //======== scrollPane11 ======== + { + scrollPane11.setName("scrollPane11"); + + //---- textPane3 ---- + textPane3.setText("longer text for testing horizontal scrolling"); + textPane3.setComponentPopupMenu(popupMenu1); + textPane3.setName("textPane3"); + scrollPane11.setViewportView(textPane3); + } + add(scrollPane11, "cell 2 5,growx"); + + //---- comboBoxLabel ---- + comboBoxLabel.setText("JComboBox:"); + comboBoxLabel.setDisplayedMnemonic('C'); + comboBoxLabel.setLabelFor(comboBox1); + comboBoxLabel.setName("comboBoxLabel"); + add(comboBoxLabel, "cell 0 6"); + + //---- comboBox1 ---- + comboBox1.setEditable(true); + comboBox1.setModel(new DefaultComboBoxModel<>(new String[] { + "editable", + "a", + "bb", + "ccc" + })); + comboBox1.setComponentPopupMenu(popupMenu1); + comboBox1.setName("comboBox1"); + add(comboBox1, "cell 1 6,growx"); + + //---- comboBox3 ---- + comboBox3.setModel(new DefaultComboBoxModel<>(new String[] { + "longer text for testing horizontal scrolling", + "a", + "bb", + "ccc" + })); + comboBox3.setEditable(true); + comboBox3.setPrototypeDisplayValue("12345"); + comboBox3.setComponentPopupMenu(popupMenu1); + comboBox3.setName("comboBox3"); + add(comboBox3, "cell 2 6,growx"); + + //---- spinnerLabel ---- + spinnerLabel.setText("JSpinner:"); + spinnerLabel.setDisplayedMnemonic('S'); + spinnerLabel.setLabelFor(spinner1); + spinnerLabel.setName("spinnerLabel"); + add(spinnerLabel, "cell 0 7"); + + //---- spinner1 ---- + spinner1.setComponentPopupMenu(popupMenu1); + spinner1.setName("spinner1"); + add(spinner1, "cell 1 7,growx"); + + //======== popupMenu1 ======== + { + popupMenu1.setName("popupMenu1"); + + //---- cutMenuItem ---- + cutMenuItem.setText("Cut"); + cutMenuItem.setName("cutMenuItem"); + popupMenu1.add(cutMenuItem); + + //---- copyMenuItem ---- + copyMenuItem.setText("Copy"); + copyMenuItem.setName("copyMenuItem"); + popupMenu1.add(copyMenuItem); + + //---- pasteMenuItem ---- + pasteMenuItem.setText("Paste"); + pasteMenuItem.setName("pasteMenuItem"); + popupMenu1.add(pasteMenuItem); + } + // JFormDesigner - End of component initialization //GEN-END:initComponents + + cutMenuItem.addActionListener( new DefaultEditorKit.CutAction() ); + copyMenuItem.addActionListener( new DefaultEditorKit.CopyAction() ); + pasteMenuItem.addActionListener( new DefaultEditorKit.PasteAction() ); + } + + // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables + private JTextField textField1; + // JFormDesigner - End of variables declaration //GEN-END:variables +} 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 new file mode 100644 index 00000000..abb9aa08 --- /dev/null +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.jfd @@ -0,0 +1,259 @@ +JFDML JFormDesigner: "7.0.0.0.194" Java: "13.0.1" encoding: "UTF-8" + +new FormModel { + contentType: "form/swing" + root: new FormRoot { + "$setComponentNames": true + auxiliary() { + "JavaCodeGenerator.defaultVariableLocal": true + } + add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { + "$layoutConstraints": "ltr,insets dialog,hidemode 3" + "$columnConstraints": "[][][::100][100,fill][fill]" + "$rowConstraints": "[][][][50,fill][50,fill][50,fill][][]" + } ) { + name: "this" + add( new FormComponent( "javax.swing.JLabel" ) { + name: "textFieldLabel" + "text": "JTextField:" + "displayedMnemonic": 84 + "labelFor": new FormReference( "textField1" ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 0" + } ) + add( new FormComponent( "javax.swing.JTextField" ) { + name: "textField1" + "text": "editable" + "componentPopupMenu": &FormReference0 new FormReference( "popupMenu1" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 0,growx" + } ) + add( new FormComponent( "javax.swing.JTextField" ) { + name: "textField3" + "text": "longer text for testing horizontal scrolling" + "componentPopupMenu": #FormReference0 + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 0,growx" + } ) + add( new FormComponent( "javax.swing.JTextField" ) { + name: "textField2" + "text": "partly selected" + "selectionStart": 1 + "selectionEnd": 4 + "componentPopupMenu": #FormReference0 + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 3 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 4 0" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "formattedTextFieldLabel" + "text": "JFormattedTextField:" + "displayedMnemonic": 70 + "labelFor": new FormReference( "formattedTextField1" ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 1" + } ) + add( new FormComponent( "javax.swing.JFormattedTextField" ) { + name: "formattedTextField1" + "text": "editable" + "componentPopupMenu": #FormReference0 + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 1,growx" + } ) + add( new FormComponent( "javax.swing.JFormattedTextField" ) { + name: "formattedTextField3" + "text": "longer text for testing horizontal scrolling" + "componentPopupMenu": #FormReference0 + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 1,growx" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "passwordFieldLabel" + "text": "JPasswordField:" + "displayedMnemonic": 80 + "labelFor": new FormReference( "passwordField1" ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 2" + } ) + add( new FormComponent( "javax.swing.JPasswordField" ) { + name: "passwordField1" + "text": "editable" + "componentPopupMenu": #FormReference0 + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 2,growx" + } ) + add( new FormComponent( "javax.swing.JPasswordField" ) { + name: "passwordField3" + "text": "longer text for testing horizontal scrolling" + "componentPopupMenu": #FormReference0 + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 2,growx" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "textAreaLabel" + "text": "JTextArea:" + "displayedMnemonic": 65 + "labelFor": new FormReference( "textArea1" ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 3" + } ) + add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) { + name: "scrollPane1" + add( new FormComponent( "javax.swing.JTextArea" ) { + name: "textArea1" + "text": "editable" + "componentPopupMenu": #FormReference0 + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 3,growx" + } ) + add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) { + name: "scrollPane3" + add( new FormComponent( "javax.swing.JTextArea" ) { + name: "textArea3" + "text": "longer text for testing horizontal scrolling" + "componentPopupMenu": #FormReference0 + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 3,growx" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "editorPaneLabel" + "text": "JEditorPane" + "displayedMnemonic": 74 + "labelFor": new FormReference( "editorPane1" ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 4" + } ) + add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) { + name: "scrollPane5" + add( new FormComponent( "javax.swing.JEditorPane" ) { + name: "editorPane1" + "text": "editable" + "componentPopupMenu": #FormReference0 + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 4,growx" + } ) + add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) { + name: "scrollPane7" + add( new FormComponent( "javax.swing.JEditorPane" ) { + name: "editorPane3" + "text": "longer text for testing horizontal scrolling" + "componentPopupMenu": #FormReference0 + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 4,growx" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "textPaneLabel" + "text": "JTextPane:" + "displayedMnemonic": 78 + "labelFor": new FormReference( "textPane1" ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 5" + } ) + add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) { + name: "scrollPane9" + add( new FormComponent( "javax.swing.JTextPane" ) { + name: "textPane1" + "text": "editable" + "componentPopupMenu": #FormReference0 + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 5,growx" + } ) + add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) { + name: "scrollPane11" + add( new FormComponent( "javax.swing.JTextPane" ) { + name: "textPane3" + "text": "longer text for testing horizontal scrolling" + "componentPopupMenu": #FormReference0 + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 5,growx" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "comboBoxLabel" + "text": "JComboBox:" + "displayedMnemonic": 67 + "labelFor": new FormReference( "comboBox1" ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 6" + } ) + add( new FormComponent( "javax.swing.JComboBox" ) { + name: "comboBox1" + "editable": true + "model": new javax.swing.DefaultComboBoxModel { + selectedItem: "editable" + addElement( "editable" ) + addElement( "a" ) + addElement( "bb" ) + addElement( "ccc" ) + } + "componentPopupMenu": #FormReference0 + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 6,growx" + } ) + add( new FormComponent( "javax.swing.JComboBox" ) { + name: "comboBox3" + "model": new javax.swing.DefaultComboBoxModel { + selectedItem: "longer text for testing horizontal scrolling" + addElement( "longer text for testing horizontal scrolling" ) + addElement( "a" ) + addElement( "bb" ) + addElement( "ccc" ) + } + "editable": true + "prototypeDisplayValue": "12345" + "componentPopupMenu": #FormReference0 + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 6,growx" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "spinnerLabel" + "text": "JSpinner:" + "displayedMnemonic": 83 + "labelFor": new FormReference( "spinner1" ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 7" + } ) + add( new FormComponent( "javax.swing.JSpinner" ) { + name: "spinner1" + "componentPopupMenu": #FormReference0 + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 7,growx" + } ) + }, new FormLayoutConstraints( null ) { + "location": new java.awt.Point( 0, 0 ) + "size": new java.awt.Dimension( 530, 340 ) + } ) + add( new FormContainer( "javax.swing.JPopupMenu", new FormLayoutManager( class javax.swing.JPopupMenu ) ) { + name: "popupMenu1" + add( new FormComponent( "javax.swing.JMenuItem" ) { + name: "cutMenuItem" + "text": "Cut" + } ) + add( new FormComponent( "javax.swing.JMenuItem" ) { + name: "copyMenuItem" + "text": "Copy" + } ) + add( new FormComponent( "javax.swing.JMenuItem" ) { + name: "pasteMenuItem" + "text": "Paste" + } ) + }, new FormLayoutConstraints( null ) { + "location": new java.awt.Point( 0, 390 ) + "size": new java.awt.Dimension( 91, 87 ) + } ) + } +}