jsalvata    2004/01/03 17:42:52

  Modified:    src/core/org/apache/jmeter/testbeans/gui Tag:
                        testbeans_experimental_branch WrapperEditor.java
  Log:
  * Provide support for undefined (null) values.
  * Provide support for editors whose getTags() method
  returns a non-null list.
  * Added some unit tests for the issues found during
  development.
  
  Revision  Changes    Path
  No                   revision
  No                   revision
  1.1.2.2   +357 -121  
jakarta-jmeter/src/core/org/apache/jmeter/testbeans/gui/Attic/WrapperEditor.java
  
  Index: WrapperEditor.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-jmeter/src/core/org/apache/jmeter/testbeans/gui/Attic/WrapperEditor.java,v
  retrieving revision 1.1.2.1
  retrieving revision 1.1.2.2
  diff -u -r1.1.2.1 -r1.1.2.2
  --- WrapperEditor.java        1 Jan 2004 23:43:22 -0000       1.1.2.1
  +++ WrapperEditor.java        4 Jan 2004 01:42:52 -0000       1.1.2.2
  @@ -60,18 +60,20 @@
   import java.awt.Component;
   import java.awt.Graphics;
   import java.awt.Rectangle;
  -import java.awt.event.FocusEvent;
  -import java.awt.event.FocusListener;
   import java.beans.PropertyChangeListener;
   import java.beans.PropertyDescriptor;
   import java.beans.PropertyEditor;
  +import java.beans.PropertyEditorManager;
  +import java.util.Arrays;
  +import java.util.Vector;
   
  -import javax.swing.JTextField;
  -import javax.swing.text.BadLocationException;
  -import javax.swing.text.Document;
  +import javax.swing.JComboBox;
   
   import org.apache.jmeter.testbeans.TestBean;
   import org.apache.jmeter.testelement.property.JMeterProperty;
  +import org.apache.jmeter.testelement.property.NullProperty;
  +import org.apache.jmeter.testelement.property.BooleanProperty;
  +import org.apache.jmeter.testelement.property.StringProperty;
   import org.apache.jorphan.logging.LoggingManager;
   import org.apache.log.Logger;
   
  @@ -79,33 +81,108 @@
    * This class implements a property editor that wraps another PropertyEditor
    * so that:
    * <ul>
  - * <li>It handles JMeterProperty values.
  + * <li>It handles and returns JMeterProperty values wrapping the values
  + * handled and returned by the wrapped PropertyEditor.
    * <li>It provides a suitable GUI component (custom editor) for simple
    * property editors that don't have one of their own.
    * </ul>
  + * <p>
  + * For PropertyEditors that provide a custom editor, this essentially acts
  + * as a delegate, with no added functionality beyond the wrapping/unwrapping
  + * in JMeterProperties.
  + * <p>
  + * For PropertyEditors without a custom editor, the provided GUI is a combo
  + * box with:
  + * <ul>
  + * <li>An option for "undefined" (corresponding to the null value, not the
  + *      NullProperty).
  + * <li>An option for each value returned by the getTags() method on the wrapped
  + *   editor.
  + * <li>The possibility to write your own value, which will be parsed by the
  + *           wrapped editor to convert into the edited type unless (and this is an
  + *           heuristic) it contains the string "${", in which case it will be
  + *           assumed to be an 'expression' containing JMeter variables and will
  + *           not be parsed at all, but just handled as a string.
  + * </ul>
    */
  -class WrapperEditor
  -    implements PropertyEditor, FocusListener
  +class WrapperEditor implements PropertyEditor
   {
  -    private static Logger log = LoggingManager.getLoggerForClass();
  +    private static Logger log= LoggingManager.getLoggerForClass();
   
  -    PropertyEditor editor;
  -    PropertyDescriptor descriptor;
  +    private static Object UNDEFINED= new Object()
  +    {
  +        public String toString()
  +        {
  +            return "Undefined"; // TODO: should be a resource.
  +        }
  +    };
  +    // The above is a funny hack: if you use a plain String, 
  +    // entering the text of the string in the editor will make the
  +    // combo revert to that option -- which actually amounts to
  +    // making that string 'reserved'. I preferred to avoid this by
  +    // using a different type, but an object that has the same
  +    // .toString().
  +    // TODO: use a renderer that paints
  +    // the field distinct from when the same string is typed in.
  +
  +     /**
  +      * Base PropertyEditor for the property at hand. Most methods in this class
  +      * are delegated from this one.
  +      */
  +    private PropertyEditor editor;
  +    
  +    /**
  +     * Property descriptor for the property to be edited by this editor.
  +     */
  +    private PropertyDescriptor descriptor;
   
  +     /**
  +      * The type of the objects that will be assigned to or obtained from this
  +      * property. That is: the type of the property or, if this is a primitive 
  +      * type (e.g. int), the corresponding wrapping type (e.g. Integer).
  +      */
  +     private Class type;
  +     
       /**
  -     * The swing component doing the actual GUI work.
  +     * The swing component doing the actual GUI work. May be a customer
  +     * editor component provided by the delegatee editor or a combo box we
  +     * will create otherwise.
        */
  -    Component component;
  +    private Component component;
   
       /**
  -     * Copy of component if it's a text field.
  +     * Copy of component if it's the combo box we've created within this
  +     * editor, or null if the delegatee editor provides a custom editor
  +     * component. This is just a convenience to avoid having to cast
  +     * field 'component' into a JComboBox again and again. 
        */
  -    JTextField field= null;
  -     
  +    private JComboBox combo= null;
  +
       WrapperEditor(PropertyEditor editor, PropertyDescriptor descriptor)
       {
           this.editor= editor;
           this.descriptor= descriptor;
  +        
  +        type= descriptor.getPropertyType();
  +        if (type.isPrimitive())
  +        {
  +             // Sorry for this -- I have not found a better way:
  +             if (type == boolean.class) type= Boolean.class;
  +             else if (type == char.class) type= Character.class;
  +             else if (type == byte.class) type= Byte.class;
  +                     else if (type == short.class) type= Short.class;
  +             else if (type == int.class) type= Integer.class;
  +             else if (type == long.class) type= Long.class;
  +             else if (type == float.class) type= Float.class;
  +                     else if (type == double.class) type= Double.class;
  +                     else if (type == void.class) type= Void.class;
  +                     else
  +                     {
  +                             log.error("Class "+type+" is an unknown primitive 
type.");
  +             throw new Error("Class "+type+" is an unknown primitive type");
  +                     // programming error: bail out.
  +            }
  +        }
   
           if (editor.supportsCustomEditor())
           {
  @@ -113,9 +190,24 @@
           }
           else
           {
  -            field= new JTextField();
  -            field.addFocusListener(this);
  -            component= field;
  +            // Build the list of available values for this property:
  +            Vector options= new Vector();
  +
  +            // The first available value is "undefined" (null).
  +            options.add(UNDEFINED);
  +
  +            // Add the list of values given by the editor, if there is one:
  +            String[] tags= editor.getTags();
  +            if (tags != null)
  +            {
  +                options.addAll(Arrays.asList(tags));
  +            }
  +
  +            // Create the combo box we will use to edit this property:
  +            combo= new JComboBox(options);
  +            combo.setEditable(true);
  +
  +            component= combo;
           }
       }
   
  @@ -128,19 +220,6 @@
       }
   
       /* (non-Javadoc)
  -     * @see java.beans.PropertyEditor#getAsText()
  -     */
  -    public String getAsText()
  -    {
  -        String result= editor.getAsText();
  -        if (log.isDebugEnabled())
  -        {
  -            log.debug(descriptor.getName()+"->\""+result+"\"");
  -        }
  -        return result;
  -    }
  -
  -    /* (non-Javadoc)
        * @see java.beans.PropertyEditor#getCustomEditor()
        */
       public Component getCustomEditor()
  @@ -174,18 +253,178 @@
       {
           String name= descriptor.getName();
           JMeterProperty result;
  -            
  -        result= TestBean.wrapInProperty(editor.getValue());
  -        result.setName(name);
  +
  +        Object value;
  +
  +             if (editor.supportsCustomEditor())
  +             {
  +                     value= editor.getValue();
  +             }
  +             else
  +        {
  +             value= combo.getSelectedItem();
  +                     if (value == UNDEFINED)
  +                     {
  +                             value= null;
  +                     }
  +                     else {
  +                             String text= (String) value;
  +                             if (combo.getSelectedIndex() > 0
  +                                     || text.indexOf("${") == -1)
  +                             {
  +                                     // if it's not a JMeter 'expression'...
  +                                     try
  +                                     {
  +                                             editor.setAsText(text);
  +                                             value= editor.getValue();
  +                                     }
  +                                     catch (IllegalArgumentException e)
  +                                     {
  +                                             // TODO: how to warn the user?
  +                                             // Maybe we should do this check 
earlier in the edit
  +                                             // process, maybe upon 
ItemChangeEvents?
  +                                             value= null;
  +                                     }
  +                             }
  +                     }
  +        }
  +
  +             if (value != null)
  +             {
  +                     result= TestBean.wrapInProperty(value);
  +                     result.setName(name);
  +             }
  +             else result= null;
  +        
           if (log.isDebugEnabled())
           {
  -            log.debug(descriptor.getName()+"->"
  -                +(result!=null?result.getClass().getName():"NULL")
  -                +":"+result);
  +            log.debug(
  +                descriptor.getName()
  +                    + "->"
  +                    + (result != null ? result.getClass().getName() : "NULL")
  +                    + ":"
  +                    + result);
           }
           return result;
       }
   
  +     /* (non-Javadoc)
  +      * @see java.beans.PropertyEditor#setValue(java.lang.Object)
  +      */
  +     public void setValue(Object value)
  +     {
  +             if (log.isDebugEnabled())
  +             {
  +                     log.debug(
  +                             descriptor.getName()
  +                                     + "<-"
  +                                     + (value != null ? value.getClass().getName() 
: "NULL")
  +                                     + ":"
  +                                     + value);
  +             }
  +             if (value instanceof JMeterProperty)
  +             {
  +                     /*value= TestBean.unwrapProperty(
  +                             (JMeterProperty)value,
  +                             type);*/
  +                     value= ((JMeterProperty)value).getObjectValue();
  +             }
  +             if (editor.supportsCustomEditor())
  +             {
  +                     editor.setValue(value);
  +             }
  +             else
  +             {
  +                     if (value == null)
  +                     {
  +                             value= UNDEFINED;
  +                     }
  +                     else if (type.isInstance(value))
  +                     {
  +                             editor.setValue(value);
  +                             value= editor.getAsText();
  +                     }
  +                     else
  +                     {
  +                             // In this case I'll just assume value is a string -- 
I believe it
  +                             // always is but, just in case, I'll check:
  +                             if (! (value instanceof String))
  +                             {
  +                                     log.error("When editing property 
"+descriptor.getName()
  +                                             +", of type "+type
  +                                             +" got value of type 
"+value.getClass());
  +                                     throw new Error("String expected, got 
"+value.getClass());
  +                                             // programming error, so bail out.
  +                         } 
  +                     }
  +                     combo.setSelectedItem(value);
  +             }
  +     }
  +
  +     /* (non-Javadoc)
  +      * @see java.beans.PropertyEditor#getAsText()
  +      */
  +     public String getAsText()
  +     {
  +             String text;
  +             
  +             if (editor.supportsCustomEditor())
  +             {
  +                     text= editor.getAsText();
  +             }
  +             else
  +             {
  +                     Object value= combo.getSelectedItem();
  +                     if (value == UNDEFINED)
  +                     {
  +                             text= null;
  +                     }
  +                     else {
  +                             text= (String) value;
  +                             if (combo.getSelectedIndex() > 0
  +                                     || text.indexOf("${") == -1)
  +                             {
  +                                     // if it's not a JMeter 'expression'...
  +                                     editor.setAsText(text);
  +                                     text= editor.getAsText();
  +                             }
  +                     }
  +             }
  +             if (log.isDebugEnabled())
  +             {
  +                     log.debug(descriptor.getName() + "->\"" + text + "\"");
  +             }
  +             return text;
  +     }
  +
  +     /* (non-Javadoc)
  +      * @see java.beans.PropertyEditor#setAsText(java.lang.String)
  +      */
  +     public void setAsText(String text) throws IllegalArgumentException
  +     {
  +             if (log.isDebugEnabled())
  +             {
  +                     log.debug(
  +                             descriptor.getName()
  +                                     + (text == null ? "<-null" : "<-\"" + text + 
"\""));
  +             }
  +             if (editor.supportsCustomEditor())
  +             {
  +                     editor.setAsText(text);
  +             }
  +             else
  +             {
  +                     if (text == null)
  +                     {
  +                             combo.setSelectedItem(UNDEFINED);
  +                     }
  +                     else 
  +                     {
  +                             combo.setSelectedItem(text);
  +                     }
  +             }
  +     }
  +
       /* (non-Javadoc)
        * @see java.beans.PropertyEditor#isPaintable()
        */
  @@ -211,91 +450,88 @@
       }
   
       /* (non-Javadoc)
  -     * @see java.beans.PropertyEditor#setAsText(java.lang.String)
  -     */
  -    public void setAsText(String text) throws IllegalArgumentException
  -    {
  -        if (log.isDebugEnabled())
  -        {
  -            log.debug(descriptor.getName()+"<-\""+text+"\"");
  -        }
  -        if (field != null)
  -        {
  -            field.setText(text);
  -        }
  -        editor.setAsText(text);
  -    }
  -
  -    /* (non-Javadoc)
  -     * @see java.beans.PropertyEditor#setValue(java.lang.Object)
  -     */
  -    public void setValue(Object value)
  -    {
  -        if (log.isDebugEnabled())
  -        {
  -            log.debug(descriptor.getName()+"<-"
  -                +(value!=null?value.getClass().getName():"NULL")
  -                +":"+value);
  -        }
  -        if (value instanceof JMeterProperty)
  -        {
  -            value= TestBean.unwrapProperty(
  -                (JMeterProperty)value, descriptor.getPropertyType());
  -        }
  -        editor.setValue(value);
  -        if (field != null)
  -        {
  -            field.setText(editor.getAsText());
  -        }
  -    }
  -
  -    /* (non-Javadoc)
        * @see java.beans.PropertyEditor#supportsCustomEditor()
        */
       public boolean supportsCustomEditor()
       {
           return true;
       }
  -
  -    /* (non-Javadoc)
  -     * @see java.awt.event.FocusListener#focusGained(java.awt.event.FocusEvent)
  -     */
  -    public void focusGained(FocusEvent e)
  -    {
  -        // no-op
  -    }
  -
  -    /* (non-Javadoc)
  -     * @see java.awt.event.FocusListener#focusLost(java.awt.event.FocusEvent)
  -     */
  -    public void focusLost(FocusEvent e)
  -    {
  -        // Copy our data back to the property editor:
  -            
  -        Document d= field.getDocument();
  -        String text;
  -        try
  -        {
  -            text= d.getText(0, d.getLength());
  -        }
  -        catch (BadLocationException e1)
  -        {
  -            log.error("This can't happen!", e1);
  -            throw new Error(e1); // Bail out.
  -        }
  -
  -        if (log.isDebugEnabled())
  -        {
  -            log.debug(descriptor.getName()+": "+text);
  -        }
  -
  -        try
  -        {
  -            editor.setAsText(text);
  -        }
  -        catch (IllegalArgumentException e1)
  -        {
  -            // TODO: report to the user??
  -        }
  -    }
  -}
  +    
  +     public static class Test extends junit.framework.TestCase
  +     {
  +             public Test(String name)
  +             {
  +                     super(name);
  +             }
  +             
  +             private abstract class ABean {
  +                     public abstract void setB(boolean b);
  +                     public abstract boolean getB();
  +                     public abstract void setS(String b);
  +                     public abstract String getS();
  +             }
  +             
  +             private void testSetGet(WrapperEditor e, Object value) throws Exception
  +             {
  +                     e.setValue(value);
  +                     assertEquals(value, e.getValue());
  +             }
  +             private void testSetGetAsText(WrapperEditor e, String text) throws 
Exception
  +             {
  +                     e.setAsText(text);
  +                     assertEquals(text, e.getAsText());
  +             }
  +             public void testSetGetOnSimpleEditor() throws Exception
  +             {
  +                     WrapperEditor e= new WrapperEditor(
  +                             PropertyEditorManager.findEditor(boolean.class), 
  +                             new PropertyDescriptor("B", ABean.class));
  +                             
  +                     testSetGet(e, new BooleanProperty("B", true));
  +                     testSetGet(e, new BooleanProperty("B", false));
  +                     testSetGet(e, null);
  +                     testSetGet(e, new StringProperty("B", "${var}"));
  +                     
  +                     e.setValue(new StringProperty("B", "true"));
  +                     assertEquals(new BooleanProperty("B", true), e.getValue());
  +
  +                     e.setValue(new StringProperty("B", "True"));
  +                     assertEquals(new BooleanProperty("B", true), e.getValue());
  +             }
  +             public void testSetGetAsTextOnSimpleEditor() throws Exception
  +             {
  +                     WrapperEditor e= new WrapperEditor(
  +                             PropertyEditorManager.findEditor(boolean.class), 
  +                             new PropertyDescriptor("B", ABean.class));
  +                             
  +                     testSetGetAsText(e, "True");
  +                     testSetGetAsText(e, "False");
  +                     testSetGetAsText(e, null);
  +                     testSetGetAsText(e, "${var}");
  +                     
  +                     e.setAsText("true");
  +                     assertEquals(new BooleanProperty("B", true), e.getValue());
  +
  +                     e.setAsText("True");
  +                     assertEquals(new BooleanProperty("B", true), e.getValue());
  +                     
  +                     e.setAsText("invalid");
  +                     assertEquals(null, e.getValue());
  +             }
  +             public void testSetGetAsTextOnString() throws Exception
  +             {
  +                     WrapperEditor e= new WrapperEditor(
  +                             PropertyEditorManager.findEditor(String.class), 
  +                             new PropertyDescriptor("S", ABean.class));
  +                             
  +                     testSetGetAsText(e, "any string");
  +                     testSetGetAsText(e, "");
  +                     testSetGetAsText(e, null);
  +                     testSetGetAsText(e, "${var}");
  +                     
  +                     // Check "Undefined" does not become a "reserved word":
  +                     e.setAsText(UNDEFINED.toString());
  +                     assertNotNull(e.getValue());
  +             }
  +     }
  +}
  \ No newline at end of file
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to