Browse Source

Add hashtag support to color picker hex input fields

Co-authored-by: neph1 <[email protected]>
copilot-swe-agent[bot] 3 weeks ago
parent
commit
cb3a39509d

+ 79 - 0
jme3-core/src/com/jme3/gde/core/properties/ColorRGBADialog.java

@@ -64,6 +64,7 @@ public class ColorRGBADialog extends javax.swing.JDialog {
         super(parent, modal);
         this.editor = editor;
         initComponents();
+        setupHashtagColorCodeSupport();
         fromColor((ColorRGBA)editor.getValue());
     }
 
@@ -213,6 +214,84 @@ public class ColorRGBADialog extends javax.swing.JDialog {
         }
     }//GEN-LAST:event_alphaSliderStateChanged
 
+    /**
+     * Sets up hashtag support for hex color code input in the JColorChooser.
+     * This allows users to paste HTML color codes starting with '#' (e.g., #a6f5fe).
+     */
+    private void setupHashtagColorCodeSupport() {
+        setupHashtagSupportRecursive(jColorChooser1);
+    }
+    
+    /**
+     * Recursively searches for text fields in the color chooser and adds
+     * hashtag handling to any that might contain hex color codes.
+     */
+    private void setupHashtagSupportRecursive(java.awt.Container container) {
+        for (java.awt.Component component : container.getComponents()) {
+            if (component instanceof javax.swing.JTextField) {
+                javax.swing.JTextField textField = (javax.swing.JTextField) component;
+                addHashtagSupport(textField);
+            } else if (component instanceof java.awt.Container) {
+                setupHashtagSupportRecursive((java.awt.Container) component);
+            }
+        }
+    }
+    
+    /**
+     * Adds hashtag support to a text field by filtering out leading '#' characters
+     * when the field loses focus or when Enter is pressed.
+     */
+    private void addHashtagSupport(javax.swing.JTextField textField) {
+        // Add a focus listener to handle hashtag removal when field loses focus
+        textField.addFocusListener(new java.awt.event.FocusAdapter() {
+            @Override
+            public void focusLost(java.awt.event.FocusEvent evt) {
+                processHashtagInput(textField);
+            }
+        });
+        
+        // Add an action listener to handle hashtag removal when Enter is pressed
+        textField.addActionListener(new java.awt.event.ActionListener() {
+            @Override
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                processHashtagInput(textField);
+            }
+        });
+    }
+    
+    /**
+     * Processes text field input to handle hashtag prefixes.
+     * If the text starts with '#' and the rest is a valid hex string,
+     * removes the '#' and updates the field.
+     */
+    private void processHashtagInput(javax.swing.JTextField textField) {
+        String text = textField.getText().trim();
+        if (text.startsWith("#") && text.length() > 1) {
+            String hexPart = text.substring(1);
+            // Check if the part after # is a valid hex string (3 or 6 characters)
+            if (isValidHexString(hexPart)) {
+                textField.setText(hexPart);
+                // Force the color chooser to update by firing an action event
+                textField.postActionEvent();
+            }
+        }
+    }
+    
+    /**
+     * Checks if a string is a valid hex color code (3 or 6 hex digits).
+     */
+    private boolean isValidHexString(String hex) {
+        if (hex == null || (hex.length() != 3 && hex.length() != 6)) {
+            return false;
+        }
+        try {
+            Integer.parseInt(hex, 16);
+            return true;
+        } catch (NumberFormatException e) {
+            return false;
+        }
+    }
+
     // Variables declaration - do not modify//GEN-BEGIN:variables
     private javax.swing.JLabel alphaLabel;
     private javax.swing.JSlider alphaSlider;

+ 80 - 0
jme3-materialeditor/src/com/jme3/gde/materials/multiview/widgets/ColorRGBADialog.java

@@ -52,6 +52,7 @@ public class ColorRGBADialog extends javax.swing.JDialog {
     public ColorRGBADialog(java.awt.Frame parent, boolean modal) {
         super(parent, modal);
         initComponents();
+        setupHashtagColorCodeSupport();
 //        alphaSlider.setValue(Math.round(((ColorRGBA)editor.getValue()).getAlpha()*100));
     }
 
@@ -140,6 +141,85 @@ public class ColorRGBADialog extends javax.swing.JDialog {
     private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
         dispose();
     }//GEN-LAST:event_jButton2ActionPerformed
+    
+    /**
+     * Sets up hashtag support for hex color code input in the JColorChooser.
+     * This allows users to paste HTML color codes starting with '#' (e.g., #a6f5fe).
+     */
+    private void setupHashtagColorCodeSupport() {
+        setupHashtagSupportRecursive(jColorChooser1);
+    }
+    
+    /**
+     * Recursively searches for text fields in the color chooser and adds
+     * hashtag handling to any that might contain hex color codes.
+     */
+    private void setupHashtagSupportRecursive(java.awt.Container container) {
+        for (java.awt.Component component : container.getComponents()) {
+            if (component instanceof javax.swing.JTextField) {
+                javax.swing.JTextField textField = (javax.swing.JTextField) component;
+                addHashtagSupport(textField);
+            } else if (component instanceof java.awt.Container) {
+                setupHashtagSupportRecursive((java.awt.Container) component);
+            }
+        }
+    }
+    
+    /**
+     * Adds hashtag support to a text field by filtering out leading '#' characters
+     * when the field loses focus or when Enter is pressed.
+     */
+    private void addHashtagSupport(javax.swing.JTextField textField) {
+        // Add a focus listener to handle hashtag removal when field loses focus
+        textField.addFocusListener(new java.awt.event.FocusAdapter() {
+            @Override
+            public void focusLost(java.awt.event.FocusEvent evt) {
+                processHashtagInput(textField);
+            }
+        });
+        
+        // Add an action listener to handle hashtag removal when Enter is pressed
+        textField.addActionListener(new java.awt.event.ActionListener() {
+            @Override
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                processHashtagInput(textField);
+            }
+        });
+    }
+    
+    /**
+     * Processes text field input to handle hashtag prefixes.
+     * If the text starts with '#' and the rest is a valid hex string,
+     * removes the '#' and updates the field.
+     */
+    private void processHashtagInput(javax.swing.JTextField textField) {
+        String text = textField.getText().trim();
+        if (text.startsWith("#") && text.length() > 1) {
+            String hexPart = text.substring(1);
+            // Check if the part after # is a valid hex string (3 or 6 characters)
+            if (isValidHexString(hexPart)) {
+                textField.setText(hexPart);
+                // Force the color chooser to update by firing an action event
+                textField.postActionEvent();
+            }
+        }
+    }
+    
+    /**
+     * Checks if a string is a valid hex color code (3 or 6 hex digits).
+     */
+    private boolean isValidHexString(String hex) {
+        if (hex == null || (hex.length() != 3 && hex.length() != 6)) {
+            return false;
+        }
+        try {
+            Integer.parseInt(hex, 16);
+            return true;
+        } catch (NumberFormatException e) {
+            return false;
+        }
+    }
+    
     // Variables declaration - do not modify//GEN-BEGIN:variables
     private javax.swing.JLabel alphaLabel;
     private javax.swing.JSlider alphaSlider;

+ 140 - 0
jme3-materialeditor/test/unit/src/com/jme3/gde/materials/multiview/widgets/ColorRGBADialogHashtagTest.java

@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2009-2024 jMonkeyEngine
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.materials.multiview.widgets;
+
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.*;
+import javax.swing.JTextField;
+import java.lang.reflect.Method;
+
+/**
+ * Test class for hashtag color code support in ColorRGBADialog.
+ * This tests the ability to paste HTML color codes starting with '#'.
+ * 
+ * @author JMonkeyEngine Copilot
+ */
+public class ColorRGBADialogHashtagTest {
+    
+    private ColorRGBADialog dialog;
+    
+    @Before
+    public void setUp() {
+        // Create a dialog instance for testing
+        dialog = new ColorRGBADialog(null, true);
+    }
+    
+    @Test
+    public void testIsValidHexString() throws Exception {
+        // Use reflection to access the private method for testing
+        Method isValidHexStringMethod = ColorRGBADialog.class.getDeclaredMethod("isValidHexString", String.class);
+        isValidHexStringMethod.setAccessible(true);
+        
+        // Test valid 6-character hex strings
+        assertTrue((Boolean) isValidHexStringMethod.invoke(dialog, "a6f5fe"));
+        assertTrue((Boolean) isValidHexStringMethod.invoke(dialog, "A6F5FE"));
+        assertTrue((Boolean) isValidHexStringMethod.invoke(dialog, "123456"));
+        assertTrue((Boolean) isValidHexStringMethod.invoke(dialog, "ABCDEF"));
+        assertTrue((Boolean) isValidHexStringMethod.invoke(dialog, "000000"));
+        assertTrue((Boolean) isValidHexStringMethod.invoke(dialog, "FFFFFF"));
+        
+        // Test valid 3-character hex strings
+        assertTrue((Boolean) isValidHexStringMethod.invoke(dialog, "abc"));
+        assertTrue((Boolean) isValidHexStringMethod.invoke(dialog, "ABC"));
+        assertTrue((Boolean) isValidHexStringMethod.invoke(dialog, "123"));
+        assertTrue((Boolean) isValidHexStringMethod.invoke(dialog, "fff"));
+        
+        // Test invalid hex strings
+        assertFalse((Boolean) isValidHexStringMethod.invoke(dialog, null));
+        assertFalse((Boolean) isValidHexStringMethod.invoke(dialog, ""));
+        assertFalse((Boolean) isValidHexStringMethod.invoke(dialog, "ab"));    // Too short
+        assertFalse((Boolean) isValidHexStringMethod.invoke(dialog, "abcd"));  // Wrong length
+        assertFalse((Boolean) isValidHexStringMethod.invoke(dialog, "abcde")); // Wrong length
+        assertFalse((Boolean) isValidHexStringMethod.invoke(dialog, "abcdefg")); // Too long
+        assertFalse((Boolean) isValidHexStringMethod.invoke(dialog, "ghijkl")); // Invalid hex characters
+        assertFalse((Boolean) isValidHexStringMethod.invoke(dialog, "a6f5f!")); // Invalid character
+        assertFalse((Boolean) isValidHexStringMethod.invoke(dialog, "a6f5 e")); // Space character
+    }
+    
+    @Test
+    public void testProcessHashtagInput() throws Exception {
+        // Use reflection to access the private method for testing
+        Method processHashtagInputMethod = ColorRGBADialog.class.getDeclaredMethod("processHashtagInput", JTextField.class);
+        processHashtagInputMethod.setAccessible(true);
+        
+        // Test with valid hashtag input
+        JTextField textField = new JTextField();
+        textField.setText("#a6f5fe");
+        processHashtagInputMethod.invoke(dialog, textField);
+        assertEquals("a6f5fe", textField.getText());
+        
+        // Test with valid 3-character hashtag input
+        textField.setText("#abc");
+        processHashtagInputMethod.invoke(dialog, textField);
+        assertEquals("abc", textField.getText());
+        
+        // Test with uppercase hashtag input
+        textField.setText("#A6F5FE");
+        processHashtagInputMethod.invoke(dialog, textField);
+        assertEquals("A6F5FE", textField.getText());
+        
+        // Test with hashtag and spaces
+        textField.setText(" #a6f5fe ");
+        processHashtagInputMethod.invoke(dialog, textField);
+        assertEquals("a6f5fe", textField.getText());
+        
+        // Test with invalid hex after hashtag (should not change)
+        textField.setText("#ghijkl");
+        processHashtagInputMethod.invoke(dialog, textField);
+        assertEquals("#ghijkl", textField.getText()); // Should remain unchanged
+        
+        // Test with just hashtag (should not change)
+        textField.setText("#");
+        processHashtagInputMethod.invoke(dialog, textField);
+        assertEquals("#", textField.getText()); // Should remain unchanged
+        
+        // Test without hashtag (should not change)
+        textField.setText("a6f5fe");
+        processHashtagInputMethod.invoke(dialog, textField);
+        assertEquals("a6f5fe", textField.getText()); // Should remain unchanged
+        
+        // Test with invalid length (should not change)
+        textField.setText("#abcd");
+        processHashtagInputMethod.invoke(dialog, textField);
+        assertEquals("#abcd", textField.getText()); // Should remain unchanged
+        
+        // Test empty string (should not change)
+        textField.setText("");
+        processHashtagInputMethod.invoke(dialog, textField);
+        assertEquals("", textField.getText()); // Should remain unchanged
+    }
+}