alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.openide.explorer.propertysheet;

import java.awt.AWTKeyStroke;
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.DisplayMode;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.KeyboardFocusManager;
import javax.swing.JFrame;
import java.util.StringTokenizer;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
import org.openide.explorer.propertysheet.PropertySheet;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import org.openide.*;
import org.openide.nodes.*;
import org.openide.explorer.propertysheet.*;
import org.openide.explorer.propertysheet.editors.*;
import java.beans.*;
import java.lang.ref.WeakReference;
import java.lang.reflect.*;
import java.util.Hashtable;
import java.util.Iterator;
import javax.swing.*;
import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.JTextComponent;
import junit.framework.*;
import junit.textui.TestRunner;
import org.netbeans.junit.*;
import org.openide.ErrorManager;
import org.openide.util.Lookup;
import org.openide.util.Utilities;

/* A comprehensive test of EditablePropertyDisplayer */
public class EditableDisplayerTest extends NbTestCase {
    
    static {
        org.netbeans.core.NonGui.registerPropertyEditors();
    }
    
    public EditableDisplayerTest(String name) {
        super(name);
    }
    
    public static void main(String args[]) {
        TestRunner.run(suite ());
    }

    static int idx = -1;
    public static Test suite() {
        return new EditableDisplayerSuite ();
    }
    
    private static class EditableDisplayerSuite extends NbTestSuite {
        public EditableDisplayerSuite () {
            super (EditableDisplayerTest.class);
        }
        
        public void run (final TestResult tr) {
            super.run (tr);
        }
    }    
/*
 * This test creates a Property, Editor and Node. First test checks if initialized
 * editor contains the same value as property. The second checks if the property
 * value is changed if the same change will be done in the editor.
 */
   
    EditablePropertyDisplayer basicRen;
    EditablePropertyDisplayer tagsRen1;
    EditablePropertyDisplayer tagsRen2;
    EditablePropertyDisplayer tagsRen3;
    EditablePropertyDisplayer boolRen;
    EditablePropertyDisplayer custRen;
    EditablePropertyDisplayer custRen2;
    EditablePropertyDisplayer exRen;
    EditablePropertyDisplayer numRen;
    EditablePropertyDisplayer edRen;
    EditablePropertyDisplayer stringRen;

    private TNode tn;
    private BasicProperty basicProp;
    private TagsProperty tags1;
    private TagsProperty tags2;
    private TagsProperty tags3;    
    private BooleanProperty booleanProp; 
    private CustomProperty customProp;
    private CustomProperty customProp2;
    private BasicEditor te;
    private StringProperty stringProp;
    private JFrame jf=null;
    private JPanel jp=null;
    private int SLEEP_LENGTH=120;

    private static boolean setup=false;
    
    protected void tearDown() {
        /*        jf.hide();
        jf.dispose();
        Frame[] frms = Frame.getFrames();
        for (int i=0; i < frms.length; i++) {
            frms[i].hide();
            frms[i].dispose();
        }
 */
    }

    static final boolean canRun = ExtTestCase.canSafelyRunFocusTests() && GraphicsTestCase.canSafelyRunPixelTests();
    protected void setUp() throws Exception {

//            UIManager.setLookAndFeel(new com.sun.java.swing.plaf.windows.WindowsLookAndFeel());
//            UIManager.setLookAndFeel(new com.sun.java.swing.plaf.gtk.GTKLookAndFeel());
        PropUtils.forceRadioButtons=false;
        try {
//            if (setup) return;
            basicProp= new BasicProperty("basicProp", true);
            System.err.println("Created basicProp at " + System.currentTimeMillis() + " - " + basicProp);

            tags1 = new TagsProperty("tags1", true, new String[] {"What","is","the","meaning","of","life"});
            tags2 = new TagsProperty("tags2", true, new String[] {"Austrolopithecines","automatically","engender","every","one"});
            tags3 = new TagsProperty("tags3", true, new String[] {"Behold","the","power","of","cheese"});        
            booleanProp = new BooleanProperty("booleanProp", true); 
            customProp = new CustomProperty("CustomProp", true);
            customProp2 = new CustomProperty("CustomProp2", true);
            ExceptionProperty exProp = new ExceptionProperty("Exception prop", true);
            NumProperty numProp = new NumProperty("Int prop", true);
            EditableNumProperty edProp = new EditableNumProperty("Editable", true);
            stringProp = new StringProperty("stringProp",true);

            // Create new BasicEditor
            te = new BasicEditor();
            // Create new TNode
            tn = new TNode();

            System.err.println("Crating frame");
            jf = new JFrame();
            jf.getContentPane().setLayout(new BorderLayout());
            jp = new JPanel();
            jp.setLayout(new FlowLayout());
            jf.getContentPane().add(jp, BorderLayout.CENTER);
            jf.setLocation (20,20);
            jf.setSize (600, 200);

            synchronized (jp.getTreeLock()) {
                System.err.println("BasicProp = " + basicProp);

                basicRen = new EditablePropertyDisplayer(basicProp);
                tagsRen1 = new EditablePropertyDisplayer(tags1);
                tagsRen2 = new EditablePropertyDisplayer(tags2);
                tagsRen3 = new EditablePropertyDisplayer(tags3);
                boolRen = new EditablePropertyDisplayer(booleanProp);
                custRen = new EditablePropertyDisplayer(customProp);
                custRen2 = new EditablePropertyDisplayer(customProp2);
                exRen = new EditablePropertyDisplayer(exProp);
                numRen = new EditablePropertyDisplayer(numProp);
                edRen = new EditablePropertyDisplayer(edProp);
                stringRen = new EditablePropertyDisplayer(stringProp);

                tagsRen2.setRadioButtonMax(10);

                jp.add(basicRen);
                jp.add(tagsRen1);
                jp.add(tagsRen2);
                jp.add(tagsRen3);
                jp.add(boolRen);
                jp.add(custRen);
                jp.add(custRen2);
                jp.add(numRen);
                jp.add(edRen);
                jp.add(stringRen);
            }

            System.err.println("Waiting for window");
            new WaitWindow(jf);  //block until window open
            System.err.println("Window shown");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            setup = true;
        }
    }

    public void testRadioButtonThreshold() throws Exception {
        if (!canRun) return;

        System.err.println("running");
        clickOn(basicRen);
        tagsRen2.setRadioButtonMax(2); 

        clickOn(tagsRen2);
        Component c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
        assertTrue("after setting radio max below threshold, click on the renderer should focus a combo box, not " + c, c instanceof JComboBox);

        clickOn(basicRen);
        tagsRen2.setRadioButtonMax(10);
        sleep();

        clickOn(tagsRen2, 80, 25);
        tagsRen2.requestFocus();
        sleep();

        c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
        assertTrue("after setting radio button max > threshold, focus owner should be a radio button, not " + c, c instanceof JRadioButton);
    }
    
    public void testBooleanEditor() throws Exception {
        if (!canRun) return;

        boolRen.setUpdatePolicy(boolRen.UPDATE_ON_CONFIRMATION);
        requestFocus(boolRen);
        sleep();
        sleep();
        Component c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
        assertTrue ("After requesting focus on a boolean property, focus owner should be a checkbox, not " + c, c instanceof JCheckBox);
        
        Boolean b = (Boolean) booleanProp.getValue();
        pressKey(boolRen, KeyEvent.VK_SPACE);
        releaseKey(boolRen, KeyEvent.VK_SPACE);
        Boolean b2 = (Boolean) booleanProp.getValue();
        assertNotSame ("Clicking on a checkbox with policy UPDATE_ON_CONFIRMATION should change the property value",b, b2);
        
        boolRen.setUpdatePolicy(boolRen.UPDATE_ON_EXPLICIT_REQUEST);
        Boolean b3 = (Boolean) booleanProp.getValue();
        pressKey(boolRen, KeyEvent.VK_SPACE);
        releaseKey(boolRen, KeyEvent.VK_SPACE);
        Boolean b4 = (Boolean) booleanProp.getValue();
        assertEquals("Clicking on a checkbox with policy UPDATE_ON_EXPLICIT_REQUEST should not change the underlying property", b3, b4);
        
        Boolean b5 = (Boolean) boolRen.getEnteredValue();
        assertNotSame ("Clicking on a checkbox wiith policy UDPATE_ON_EXPLICIT_REQUEST should mean that the value returned by the editor and the value returned by the property are different until commit() is called",
            b4, b5);
        
        boolean rslt = boolRen.commit();
        assertTrue("Should have been able to update boolean property", rslt);
        
        Boolean b6 = (Boolean) booleanProp.getValue();
        assertEquals("After commit, bool editor value should eqaul bool property value", b6, boolRen.getEnteredValue());
        
        pressKey(boolRen, KeyEvent.VK_SPACE);
        releaseKey(boolRen, KeyEvent.VK_SPACE);
        
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                jf.getContentPane().remove(boolRen);
            }
        });
        sleep();
        
        boolean val = boolRen.commit();
        assertTrue ("Should still be able to commit after removal from a parent", val);
        
        assertNotSame("Commit should update value even if called when no parent is present", b6, booleanProp.getValue());
    }
     
    public void testEditableCombo() throws Exception{
        if (!canRun) return;

        edRen.setUpdatePolicy(edRen.UPDATE_ON_CONFIRMATION);
        clickOn (edRen);
        requestFocus(edRen);
        sleep();
        sleep();
        JComponent c = (JComponent)KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
        
        
        Object o = edRen.getProperty().getValue();
        String nuVal = "FOO";
        
        typeKey (c, KeyEvent.VK_F);
        typeKey (c, KeyEvent.VK_O);
        typeKey (c, KeyEvent.VK_O);
        assertEquals("After typing into editable combo, value should match the typed value", nuVal, edRen.getEnteredValue());

        assertNotSame("After typing into editable combo with policy UPDATE_ON_CONFIRMATION, the property should not have the value typed",
            nuVal, edRen.getProperty().getValue());
        
        pressKey(c, KeyEvent.VK_ENTER);
        
        assertEquals("After pressing enter on an editable combo, value should be updated", nuVal, edRen.getProperty().getValue());
    }
    
    public void testEnv() throws Exception {
        if (!canRun) return;

        try {
        custRen.setUpdatePolicy(custRen.UPDATE_ON_EXPLICIT_REQUEST);
        
        requestFocus(custRen);
        JComponent c = (JComponent)KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
        typeKey (c, KeyEvent.VK_W);
        typeKey (c, KeyEvent.VK_O);
        typeKey (c, KeyEvent.VK_W);
        pressKey(c, KeyEvent.VK_ENTER);
        
        EditorCustom ec = (EditorCustom) custRen.getPropertyEditor();
        PropertyEnv env = ec.env;
        assertSame (" The PropertyEnv the editor is attached to should be the same as the one the component posesses", 
            custRen.getPropertyEnv(), env);
        
        assertTrue (" After pressing enter with a new value with policy UPDATE_ON_EXPLICIT_REQUEST, the property value should not be the typed value",
            !custRen.getProperty().getValue().equals("WOW"));
         
        assertTrue (" After pressing enter with a new value with policy UPDATE_ON_EXPLICIT_REQUEST, isValueModified() should return true",
            custRen.isValueModified());
        
        env = ec.env;
        assertSame (" Calling isValueModified attached a different PropertyEnv to the editor and didn't call attachEnv again with the one it listens on for changes", 
            custRen.getPropertyEnv(), env);
        
        
        String legality = custRen.isModifiedValueLegal();
        assertNull ("After pressing enter with a new value with policy UPDATE_ON_EXPLICIT_REQUEST with a valid value, isModifiedValueLegal should return null, not " + legality,
            legality);
        
        env = ec.env;
        
        env = ec.env;
        assertSame (" Calling isModifiedValueLegal attached a different PropertyEnv to the editor and didn't call attachEnv again with the one it listens on for changes", 
            custRen.getPropertyEnv(), env);
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
        
        requestFocus(basicRen);
        
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                custRen.setEnteredValue("");
            }
        });
        sleep();
        sleep();
        sleep();
        
        requestFocus(custRen);
        
        typeKey(custRen, KeyEvent.VK_V);
        typeKey(custRen, KeyEvent.VK_A);
        typeKey(custRen, KeyEvent.VK_L);
        typeKey(custRen, KeyEvent.VK_U);
        typeKey(custRen, KeyEvent.VK_E);
        
        pressKey(custRen, KeyEvent.VK_ENTER);
        
        assertEquals ("After entering a value, getEnteredValue should return it", "VALUE", custRen.getEnteredValue());
        

        String legality = custRen.isModifiedValueLegal();
        assertNotNull("After entering a value that will put the env in STATE_INVALID, a localized message should be returned by isModifiedValueLegal", legality);
        
    }
    
    
    public void testPropertyMarking() throws Exception{
        if (!canRun) return;

        if (!checkGraphicsEnvironment()) {
            System.err.println("  Cannot run this test in a < 16 bit graphics environment");
        }
        custRen.setUpdatePolicy(custRen.UPDATE_ON_CONFIRMATION);
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                try {
                throwMe = null;
                custRen.getProperty().setValue("Value");
                custRen.refresh();
                } catch (Exception e) {
                    throwMe = e;
                }
            }
        });
    
        if (throwMe != null) {
            Exception exc = throwMe;
            throwMe = null;
            throw exc;
        }
        
        
        requestFocus(custRen);
        
        typeKey(custRen, KeyEvent.VK_S);
        typeKey(custRen, KeyEvent.VK_N);
        typeKey(custRen, KeyEvent.VK_O);
        typeKey(custRen, KeyEvent.VK_R);
        typeKey(custRen, KeyEvent.VK_K);
        typeKey(custRen, KeyEvent.VK_E);
        typeKey(custRen, KeyEvent.VK_L);
        
        //The property marking image
        Image i = Utilities.loadImage("org/openide/resources/propertysheet/invalid.gif");
        ImageIcon icon = new ImageIcon(i);
        int yOffset = (custRen.getHeight() / 2) - (icon.getIconHeight()/2);
        
//        assertPixelFromImage(i, custRen, 7, 7, 7, yOffset + 7);
        assertImageMatch("Error icon should be painted for invalid value", i, custRen, 0, yOffset);
        
        requestFocus(custRen);
        
//        SLEEP_LENGTH=1000;
        sleep();
        typeKey(custRen, KeyEvent.VK_M);
        typeKey(custRen, KeyEvent.VK_R);
        typeKey(custRen, KeyEvent.VK_F);
        typeKey(custRen, KeyEvent.VK_ENTER);
        pressKey(custRen, KeyEvent.VK_ENTER);
        pressKey(custRen, KeyEvent.VK_ENTER);
        custRen.commit();
        sleep();
        sleep();
        
        Icon icon2 = new ValueIcon();
        int yOffset2 = (custRen.getHeight() / 2) - (icon2.getIconHeight()/2);
        
        assertPixel("Supplied value icon should be drawn on panel, not the error marking icon, after committing a valid value.", 
            custRen, Color.BLUE, icon2.getIconWidth() / 2, (icon2.getIconHeight() / 2) + yOffset2);
        
        requestFocus(custRen);
        
        typeKey(custRen, KeyEvent.VK_V);
        typeKey(custRen, KeyEvent.VK_A);
        typeKey(custRen, KeyEvent.VK_L);
        typeKey(custRen, KeyEvent.VK_U);
        typeKey(custRen, KeyEvent.VK_E);
        custRen.setEnteredValue("VALUE");
        pressKey(custRen, KeyEvent.VK_ENTER);
        custRen.commit();
        sleep();
        sleep();
        sleep();
        custRen.paintImmediately(0,0,custRen.getWidth(),custRen.getHeight());
        assertImageMatch("After reentering an invalid value, the icon should change back to the error icon", i, custRen, 0, yOffset);
    }
    
    
    
    public void testControlSpaceInvokesCustomEditor() throws Exception {
        if (!canRun) return;

        requestFocus(custRen2);
        final Component focusOwner = 
            KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
        assertTrue ("Requesting focus on an enabled renderer should set focus to it or its child", custRen2 == focusOwner || custRen2.isAncestorOf(focusOwner));
        
        System.err.println("CONTROL PRESS KEY");
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                try {
                    throwMe = null;
                    ctrlPressKey(focusOwner, KeyEvent.VK_SPACE);
                } catch (Exception e) {
                    throwMe = e;
                }
            }
        });
        if (throwMe != null) {
            Exception e1 = throwMe;
            throwMe = null;
            throw throwMe;
        }
        
        sleep();
        sleep();
        sleep();
        sleep();
        sleep();
        sleep();
        
        Component newOwner = 
            KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
        
        assertNotSame("Pressing ctrl-space should move focus to a dialog", focusOwner, newOwner);
        
        pressKey (newOwner, KeyEvent.VK_ESCAPE);
        sleep();

        Component owner = 
            KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();

        if (owner == null) {
            sleep();
            sleep();
            owner =
                KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
        }
        
        assertNotSame("Pressing escape on custom editor dialog should dismiss it", owner, newOwner);
        assertSame("Focus should return to the editor if lost from a custom editor dialog", focusOwner, owner);
        
        if (newOwner != null) {
            Container c = ((JComponent) newOwner).getTopLevelAncestor();
            if (c != null) {
                c.hide();
            }
        }
    }

    public void testRenderersPaintIndentically() throws Exception {
        if (!canRun) return;
        if (!checkGraphicsEnvironment()) {
            System.err.println("Cannot run test in < 16 bit graphics environment");
        }
        Component[] c = jp.getComponents();
        Hashtable map = new Hashtable();
        synchronized (jp.getTreeLock()) {
            for (int i=0; i < c.length; i++) {
                System.err.println("  Checking " + c[i]);
                if (c[i] instanceof EditablePropertyDisplayer) {
                    System.err.println(" CREATE A RENDERER AND ADD IT");
                    EditablePropertyDisplayer curr = (EditablePropertyDisplayer) c[i];
                    try {
                        curr.commit();
                    } catch (Exception e) {
                        curr.reset();
                    }
                    
                    RendererPropertyDisplayer rpd = new RendererPropertyDisplayer(curr.getProperty());
                    rpd.setRadioButtonMax(curr.getRadioButtonMax());
                    rpd.setProperty(curr.getProperty());
                    map.put(curr, rpd);
                    jp.add(rpd);
                }
            }
        }
        
        jp.repaint();
        
        
        Iterator i = map.keySet().iterator();
        while (i.hasNext()) {
            EditablePropertyDisplayer editable = (EditablePropertyDisplayer) i.next();
            RendererPropertyDisplayer renderer = (RendererPropertyDisplayer) map.get(editable);
            assertPaintIdentically("Painting was not a pixel-for-pixel match between " + editable + " and " + renderer, editable, renderer);
//            assertEquals("Preferred size of a renderer and an editor should match.  They do not for " + editable + " and " + renderer, getPreferredSize(editable), getPreferredSize(renderer));
        }
        
    }
     
    
    public void testCustomEditor() throws Exception {
        if (!canRun) return;

        requestFocus(stringRen);
        Runnable run = new Runnable() {
            public void run() {
                try {
                    doCtrlPressKey(stringRen, KeyEvent.VK_SPACE);
                } catch (Exception e) {}
            }
        };
        new Thread(run).start();
        
        Thread.currentThread().sleep(1000);
        
        sleep();
        Component owner = 
            KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();

        assertNotNull("After invoking custom editor, focus owner should not be null", owner);
        
        assertTrue ("Control press should invoke custom editor", ((JComponent) owner).getTopLevelAncestor() !=
            stringRen.getTopLevelAncestor());
        
        assertTrue ("String custom editor should be a JTextComponent", owner instanceof JTextComponent);
        
        final JTextComponent jtc = (JTextComponent) owner;
        
        jtc.setText("Wuggle buggle");
        
        sleep();
        sleep();
        
        doCtrlPressKey(owner, KeyEvent.VK_TAB);
        
        sleep();
        sleep();
        
        Component okbutton = 
            KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
        
        assertTrue ("Button after editor in string renderer should be ok button", okbutton instanceof JButton);
        
        ((JButton) okbutton).doClick();
        sleep();
        sleep();
        sleep();
        
        assertEquals("After clicking ok on custom editor, property should be updated", "Wuggle buggle", stringRen.getProperty().getValue());
        sleep();
        assertEquals("After clicking ok button, inline editor should have the custom editor value", stringRen.getProperty().getValue(), stringRen.getEnteredValue());
        
    }
    
    public void testCustomEditorTitle() throws Exception {
        if (!canRun) return;

        requestFocus (custRen);
        Runnable run = new Runnable() {
            public void run() {
                try {
                    doCtrlPressKey(stringRen, KeyEvent.VK_SPACE);
                } catch (Exception e) {}
            }
        };
        new Thread(run).start();
        
        Thread.currentThread().sleep(1000);
        
        sleep();
        Component owner = 
            KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();

        assertTrue ("Control press should invoke custom editor", ((JComponent) owner).getTopLevelAncestor() !=
            stringRen.getTopLevelAncestor());
        
        Container c = ((JComponent) owner).getTopLevelAncestor();
        System.err.println("CLASS: " + c.getClass());
        
        if (c instanceof JDialog) {
            assertEquals("Custom editor supplying a title via client properties should be shown in a dialog with that title",
                ((JDialog) c).getTitle(), "Don't panic");
        }
    }
    
    private Dimension dim=null;
    /** Fetches a preferred size on the event thread.  This will actually cause
     * intermittent failures otherwise, becuase the layout can be asekd for
     * preferred size while components are still being added */
    private Dimension getPreferredSize(final JComponent jc) throws Exception {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                dim = null;
                throwMe = null;
                try {
                    dim = jc.getPreferredSize();
                } catch (Exception e) {
                    throwMe = e;
                }
            }
        });
        Dimension result = dim;
        dim = null;
        if (throwMe != null) {
            Exception exc = throwMe;
            throwMe = null;
            throw throwMe;
        }
        return result;
    }
    
    private void assertPaintIdentically (String msg, JComponent a, JComponent b) throws Exception {

        if (true) return; //Don't enable these tests by default

        //do this so focus rectangle won't produce a false non-match
        KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
        
        final Dimension d = getPreferredSize(a);
        
        if (d.width < 0 || d.height < 0) {
            StringBuffer sb = new StringBuffer();
            Container con = a;
            while (con != null && con.getComponentCount() != 0) {
                sb.append(con.getClass().getName() + " - preferred size: " + con.getPreferredSize() + "\n");
                if (con.getComponent(0) instanceof Container) {
                    con = (Container) con.getComponent(0);
                } else {
                    con = null;
                }
            }
            fail ("Got a negative preferred size: " + d + " from tree " + sb.toString());
        }
        
        final BufferedImage bia = new BufferedImage (d.width, d.height, BufferedImage.TYPE_INT_RGB);
        final BufferedImage bib = new BufferedImage (d.width, d.height, BufferedImage.TYPE_INT_RGB);
        System.err.println("Created an image of size " + d);
        
        Graphics2D ga = (Graphics2D) bia.getGraphics();
        
        a.setBounds(0, 0, d.width, d.height);
        if (a.getLayout() != null) {
            a.getLayout().layoutContainer(a);
        }
        
        sleep();
        sleep();
        try {
            a.paint(ga);
        } catch (Exception e) {
            SwingUtilities.paintComponent(ga, a, jp, 0, 0, d.width, d.height);
        }
        
        Graphics2D gb = (Graphics2D) bib.getGraphics();
        b.setBounds(0,0,d.width,d.height);
        if (b.getLayout() != null) {
            b.getLayout().layoutContainer(a);
        }
        sleep();
        sleep();
        try {
            b.paint(gb);
        } catch (Exception e) {
            SwingUtilities.paintComponent(gb, b, jp, 0, 0, d.width, d.height);
        }
        
        final BufferedImage diff = new BufferedImage (d.width, d.height, BufferedImage.TYPE_INT_RGB);
        
        boolean match = true;
        
        for (int x=0; x < d.width; x++) {
            for (int y=0; y < d.height; y++) {
                int pixa = bia.getRGB(x, y);
                int pixb = bib.getRGB(x, y);
                boolean matches = pixa == pixb;
                if (!matches) {
                    System.err.println("Non match: " + x + "," + y);
                    diff.setRGB(x, y, 0);
                } else {
                    diff.setRGB(x, y, 1239847103);
                }
                match &= matches;
            }
        }
        
        final String classa = a.getClass().getName();
        final String classb = b.getClass().getName();
        
        
        if (!match) {
            JFrame jf = new JFrame("assertPaintIdentically diff") {
                public void paint (Graphics g) {
                    new ImageIcon (diff).paintIcon(this, g, 25, 25);
                    new ImageIcon (bia).paintIcon(this, g, 25, d.height+25);
                    new ImageIcon (bib).paintIcon(this, g, 25, d.height+d.height+25);
                    g.setColor (Color.BLUE);
                    g.drawString(classa, d.width + 10, 57);
                    g.drawString(classb, d.width + 10, 82);
                }
            };
            jf.setLocation(500, 20);
            jf.setSize(d.width + 20, (d.height*3)+20);
            new WaitWindow(jf);
//            fail (msg);
        }
    }
    
    static boolean checkGraphicsEnvironment() {
        if (GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadless()) {
            System.err.println("Cannot run test in a headless environment");
        }
        DisplayMode dm = 
            GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode();
        int i = dm.getBitDepth();
        if (i == dm.BIT_DEPTH_MULTI || i >= 16) {
            return true;
        }
        return false;
    }    
    
    /** Samples a trivial number of pixels from an image and compares them with
     *pixels from a component to determine if the image is painted on the 
     * component at the exact position specified */
    private void assertImageMatch(String msg, Image i, JComponent comp, int xpos, int ypos) throws Exception {
        ImageIcon ic = new ImageIcon(i);
        int width = ic.getIconWidth();
        int height = ic.getIconHeight();
        
        for (int x=2; x < 5; x++) {
            for (int y=2; y < 5; y++) {
                int posX = width / x;
                int posY = height / y;
                System.err.println("  Check " + posX + "," + posY);
                assertPixelFromImage(msg, i, comp, posX, posY, xpos + posX, ypos + posY);
            }
        }
        
    }

    
    private void requestFocus (final JComponent jc) throws Exception {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                jc.requestFocus();
            }
        });
        sleep();
    }
    
    private class FL implements FocusListener {
        private FocusEvent gainedEvent=null;
        private FocusEvent lostEvent=null;
        private int gainedCount=0;
        private int lostCount=0;
        public void assertGained() {
            assertNotNull ("No focus gained received after clicking on an editable renderer", gainedEvent);
            assertTrue("Received wrong number of focus gained events for a single click on a renderer " +  gainedCount, gainedCount == 1);
        }
        
        public void assertLost() {
            assertNotNull ("No focus lost event received after clicking away from a focused, editable renderer", lostEvent);
            assertTrue("Received wrong number of focus lost events for a single click away from a focused renderer" + lostCount, lostCount == 1);
        }
        
        public void focusGained(java.awt.event.FocusEvent e) {
            gainedEvent = e;
            gainedCount++;
        }
        
        public void focusLost(java.awt.event.FocusEvent e) {
            lostEvent = e;
            lostCount++;
        }
    }
    
    private class CL implements ChangeListener {
        
        private ChangeEvent e;
        public void assertEvent(String msg) {
            sleep(); //give the event time to happen
            assertNotNull (msg, e);
            e = null;
        }
        
        public void assertNoEvent(String msg) {
            sleep();
            assertNull (e);
            e = null;
        }
        
        public void stateChanged(ChangeEvent e) {
            this.e = e;
        }
        
    }
    
    private static class TestGCVal extends Object {
        public String toString() {
            return "TestGCVal";
        }
    }

    private static class WaitWindow extends WindowAdapter {
        boolean shown=false;
        public WaitWindow (JFrame f) {
            f.addWindowListener(this);
            f.show();
            if (!shown) {
                synchronized(this) {
                    try {
                        //System.err.println("Waiting for window");
                            wait(5000);
                    } catch (Exception e) {}
                }
            }
        }
        
        public void windowOpened(WindowEvent e) {
            shown = true;
            synchronized(this) {
                //System.err.println("window opened");
                notifyAll();
                ((JFrame) e.getSource()).removeWindowListener(this);
            }
        }
    }
    
    private void sleep() {
         //useful when running interactively
        
        try {
            Thread.currentThread().sleep(SLEEP_LENGTH);
        } catch (InterruptedException ie) {
            //go away
        }
         
        try {
            //jf.getTreeLock().wait();
            SwingUtilities.invokeAndWait(new Runnable() {
                public void run() {
                    System.currentTimeMillis();
                }
            });
            //jf.getTreeLock().wait();
            SwingUtilities.invokeAndWait(new Runnable() {
                public void run() {
                    System.currentTimeMillis();
                }
            });            
        } catch (Exception e) {
        }
    }
    
    private static Color checkColor=null;
    private static int count=0;
    /** Asserts that a pixel at a given position in an image matches a 
     * pixel in a given position in a component */
    private synchronized void assertPixelFromImage(String msg, final Image i, final Component c, final int imageX, final int imageY, final int compX, final int compY) throws Exception {
        final BufferedImage bi = i instanceof BufferedImage ? (BufferedImage) i : toBufferedImage(i);
        throwMe = null;
        sleep();
        
        int rgb = bi.getRGB(imageX, imageY);
        Color color = new Color (rgb);
       
        
        //uncomment the code below for diagnosing painting problems
        //and seeing which pixel you'return really checking
        JFrame jf = new JFrame("assertPixelFromImage " + count + " (look for the yellow line)") {
            public void paint (Graphics g) {
                new ImageIcon (bi).paintIcon(this, g, 25, 25);
                g.setColor (Color.YELLOW);
                g.drawLine(imageX+20, imageY+25, imageX+25, imageY+25);
            }
        };
        jf.setLocation (500,500);
        jf.setSize (100,100);
        jf.show();
        
        try {
            assertPixel(msg, c, color, compX, compY);
        } catch (Exception e) {
            throwMe = e;
        }
        if (throwMe != null) {
            throw throwMe;
        }
    }
    
    private Exception throwMe2=null;
    /** Asert that a pixel at a specified position on a component is the
     *  specified color  */
    private synchronized void assertPixel(final String msg, final Component c, final Color toMatch, final int x, final int y) throws Exception {
        sleep();
        throwMe2 = null;
        if (true) {
            doAssertPixel(msg, c, toMatch, x, y);
            return;
        }
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                try {
                    doAssertPixel(msg, c, toMatch, x, y);
                } catch (Exception e) {
                    throwMe2 = e;
                }
            }
        });
        if (throwMe2 != null) {
            throw throwMe2;
        }
    }
    
    /** Implementation of assertPixel sans invokeAndWait  */
    private synchronized void doAssertPixel(final String msg, final Component c, final Color toMatch, final int x, final int y) throws Exception {
        final BufferedImage bi = new BufferedImage (700, 700, BufferedImage.TYPE_INT_RGB);

        sleep();
        ((JComponent) c).paintAll(bi.getGraphics());
        sleep();
        int[] cArr = new int[3];
        bi.getData().getPixel(x, y, cArr);
        checkColor = new Color (cArr[0], cArr[1], cArr[2]);

        
        //uncomment the code below for diagnosing painting problems
        //and seeing which pixel you'return really checking
        JFrame jf = new JFrame("Assert pixel test " + count + " (look for the yellow line)") {
            public void paint (Graphics g) {
                new ImageIcon (bi).paintIcon(this, g, 25, 25);
                g.setColor (Color.YELLOW);
                g.drawLine(x+20, y+25, x+25, y+25);
            }
        };
        jf.setLocation (400,400);
        jf.setSize (500,500);
        jf.show();
        count++;
        
        assertEquals("Pixel test " + (count-1) + " " + msg + " - Color at " + x + "," + y + " does not match", toMatch, checkColor);
    }

    
    
    private void changeProperty (final PropertyDisplayer_Mutable ren, final Node.Property newProp) throws Exception {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                ren.setProperty(newProp);
            }
        });
    }
    
    private void clickOn (final EditablePropertyDisplayer ren, final int fromRight, final int fromTop) throws Exception {
        SwingUtilities.invokeAndWait (new Runnable() {
            public void run() {
                Point toClick = new Point(ren.getWidth() - fromRight, fromTop);
                Component target=ren.getComponentAt(toClick);
                if (target == null) target = ren;
                toClick = SwingUtilities.convertPoint(ren, toClick, target);
                System.err.println("Target component is " + target.getClass().getName() + " - " + target + " clicking at " + toClick);
                
                MouseEvent me = new MouseEvent (target, MouseEvent.MOUSE_PRESSED, System.currentTimeMillis(), MouseEvent.BUTTON1_MASK, toClick.x, toClick.y, 2, false);
                target.dispatchEvent(me);
                me = new MouseEvent (target, MouseEvent.MOUSE_RELEASED, System.currentTimeMillis(), MouseEvent.BUTTON1_MASK, toClick.x, toClick.y, 2, false);
                target.dispatchEvent(me);
                me = new MouseEvent (target, MouseEvent.MOUSE_CLICKED, System.currentTimeMillis(), MouseEvent.BUTTON1_MASK, toClick.x, toClick.y, 2, false);
            }
        });
        sleep();
    }
    
    private void clickOn (final EditablePropertyDisplayer ren) throws Exception {
        SwingUtilities.invokeAndWait (new Runnable() {
            public void run() {
                Point toClick = new Point(5,5);
                Component target=ren.getComponentAt(toClick);
                System.err.println("Clicking on " + target);
                MouseEvent me = new MouseEvent (target, MouseEvent.MOUSE_PRESSED, System.currentTimeMillis(), MouseEvent.BUTTON1_MASK, toClick.x, toClick.y, 2, false);
                target.dispatchEvent(me);
            }
        });
        sleep();
    }
    
    private void setEnabled(final EditablePropertyDisplayer ren,final boolean val) throws Exception {
        SwingUtilities.invokeAndWait (new Runnable() {
            public void run() {
                ren.setEnabled(val);
            }
        });
        sleep();
    }
    
    private Exception throwMe = null;
    private String flushResult = null;
    private String flushValue(final EditablePropertyDisplayer ren) throws Exception {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                try {
                    //flushResult = ren.flushValue();
                } catch (Exception e) {
                    throwMe = e;
                    flushResult = null;
                }
            }
        });
        if (throwMe != null) {
            try {
                throw throwMe;
            } finally {
                throwMe = null;
            }
        }
        return flushResult;
    }
    

    private void releaseKey (final Component target, final int key) throws Exception {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                KeyEvent ke = new KeyEvent (target, KeyEvent.KEY_RELEASED, System.currentTimeMillis(), 0, key, (char) key);
                target.dispatchEvent(ke);
            }
        });
        sleep();
    }
    
    private void pressKey (final Component target, final int key) throws Exception {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                System.err.println("   pressKey: " + KeyStroke.getKeyStroke(key, 0).getKeyChar());
                KeyEvent ke = new KeyEvent (target, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), 0, key, (char) key);
                target.dispatchEvent(ke);
            }
        });
        sleep();
    }
    
    private void shiftPressKey (final Component target, final int key) throws Exception {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                KeyEvent ke = new KeyEvent (target, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), KeyEvent.SHIFT_MASK, key, (char) key);
                target.dispatchEvent(ke);
            }
        });
        sleep();
    }
    
    private void ctrlPressKey (final Component target, final int key) throws Exception {
        if (SwingUtilities.isEventDispatchThread()) {
            KeyEvent k = new KeyEvent (target, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), KeyEvent.CTRL_MASK, key, (char) key);
            target.dispatchEvent(k);
        } else {
            
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                KeyEvent ke = new KeyEvent (target, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), KeyEvent.CTRL_MASK, key, (char) key);
                target.dispatchEvent(ke);
            }
        });
        sleep();
        }
    }

    private void doCtrlPressKey (final Component target, final int key) throws Exception {

        KeyEvent k = new KeyEvent (target, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), KeyEvent.CTRL_MASK, key, (char) key);
        target.dispatchEvent(k);
    }

        
    private void typeKey (final Component target, final int key) throws Exception {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                System.err.println("   typeKey: " + KeyStroke.getKeyStroke(key, 0).getKeyChar());
                KeyEvent ke = new KeyEvent (target, KeyEvent.KEY_TYPED, System.currentTimeMillis(), 0, KeyEvent.VK_UNDEFINED, (char) key);
                target.dispatchEvent(ke);
            }
        });
        sleep();
    }
    
    //Node definition
    public class TNode extends AbstractNode {
        //create Node
        public TNode() {
            super (Children.LEAF);
            setName("TNode"); // or, super.setName if needed
            setDisplayName("TNode");
            createSheet();
        }
        //clone existing Node
        public Node cloneNode() {
            return new TNode();
        }
        
        public void addProp (Node.Property p) {
            props.put(p);
            this.firePropertyChange(PROP_PROPERTY_SETS, null, null);
            this.firePropertySetsChange(null, null);
        }
        
        Sheet sheet=null;
        Sheet.Set props=null;
        // Create a property sheet:
        protected Sheet createSheet() {
            sheet = super.createSheet();
            // Make sure there is a "Properties" set:
            props = sheet.get(Sheet.PROPERTIES);
            if (props == null) {
                props = Sheet.createPropertiesSet();
                sheet.put(props);
            }
            props.put(basicProp);
            props.put(tags1);
            props.put(tags2);
            props.put(tags3);
            props.put(booleanProp);
            props.put(customProp);
            
            return sheet;
        }
        // Method firing changes
        public void fireMethod(String s, Object o1, Object o2) {
            firePropertyChange(s,o1,o2);
        }
    }
    
    // Property definition
    public class BasicProperty extends PropertySupport {
        private Object myValue = "Value";
        // Create new Property
        public BasicProperty(String name, boolean isWriteable) {
            super(name, Object.class, name, "", true, isWriteable);
        }
        // get property value
        public Object getValue() {
            return myValue;
        }
        // set property value
        public void setValue(Object value) throws IllegalArgumentException,IllegalAccessException, InvocationTargetException {
            Object oldVal = myValue;
            myValue = value;
            tn.fireMethod(getName(), oldVal, myValue);
        }
        // get the property editor
        public PropertyEditor getPropertyEditor() {
            return te;
        }
    }
    
    // Editor definition
    public class BasicEditor extends PropertyEditorSupport implements ExPropertyEditor {
        PropertyEnv env;
        
        // Create new BasicEditor
        public BasicEditor() {
        }
        
        /*
         * This method is called by the IDE to pass
         * the environment to the property editor.
         */
        public void attachEnv(PropertyEnv env) {
            this.env = env;
        }
        
        // Set that this Editor doesn't support custom Editor
        public boolean supportsCustomEditor() {
            return false;
        }
        
        // Set the Property value threw the Editor
        public void setValue(Object newValue) {
            super.setValue(newValue);
        }
        
        public String getAsText() {
            return getValue() == null ? "null" : getValue().toString();
        }
    }
    
    
    private static class PseudoWindowsLookAndFeel extends com.sun.java.swing.plaf.windows.WindowsLookAndFeel {
        public boolean isSupportedLookAndFeel() {
            return true;
        }
    }

    public class TagsEditor extends PropertyEditorSupport implements ExPropertyEditor {
        PropertyEnv env;
        String[] tags;
        public TagsEditor(String[] tags) {
            this.tags = tags;
        }
        
        public String[] getTags() {
            return tags;
        }
        
        public void attachEnv(PropertyEnv env) {
            this.env = env;
        }
        
        public boolean supportsCustomEditor() {
            return false;
        }
        
        public void setValue(Object newValue) {
            super.setValue(newValue);
        }
        
        
    }
    
    // Property definition
    public class TagsProperty extends PropertySupport {
        private Object myValue = "Value";
        private String[] tags;
        // Create new Property
        public TagsProperty(String name, boolean isWriteable, String[] tags) {
            super(name, Object.class, name, "", true, isWriteable);
            this.tags = tags;
        }
        // get property value
        public Object getValue() {
            return myValue;
        }
        // set property value
        public void setValue(Object value) throws IllegalArgumentException,IllegalAccessException, InvocationTargetException {
            Object oldVal = myValue;
            myValue = value;
            tn.fireMethod(getName(), oldVal, myValue);
        }
        // get the property editor
        public PropertyEditor getPropertyEditor() {
            return new TagsEditor(tags);
        }
        
        public String getShortDescription() {
            return "I have tags!";
        }
    }
    
    // Property definition
    public class BooleanProperty extends PropertySupport {
        private Boolean myValue = Boolean.FALSE;
        // Create new Property
        public BooleanProperty(String name, boolean isWriteable) {
            super(name, Boolean.class, name, "", true, isWriteable);
        }
        // get property value
        public Object getValue() {
            System.err.println("GetValue of boolean property returning " + myValue);
            if (myValue == null) {
                throw new IllegalStateException();
            }
            return myValue;
        }
        // set property value
        public void setValue(Object value) throws IllegalArgumentException,IllegalAccessException, InvocationTargetException {
            Object oldVal = myValue;
            myValue = (Boolean) value;
            tn.fireMethod(getName(), oldVal, myValue);
        }
        public Object getValue(String key) {
            if ("valueIcon".equals(key)) {
                return new ValueIcon();
            } else {
                return super.getValue(key);
            }
        }
    }

    public class CustomProperty extends PropertySupport {
        private Object myValue = "Value";
        // Create new Property
        public CustomProperty(String name, boolean isWriteable) {
            super(name, Object.class, name, "", true, isWriteable);
        }
        // get property value
        public Object getValue() {
            return myValue;
        }
        // set property value
        public void setValue(Object value) throws IllegalArgumentException,IllegalAccessException, InvocationTargetException {
            Object oldVal = myValue;
            myValue = value;
            tn.fireMethod(getName(), oldVal, myValue);
        }
        // get the property editor
        
        private PropertyEditor editor=null;
        public PropertyEditor getPropertyEditor() {
            if (editor == null) {
                editor = new EditorCustom();
            }
            return editor;
        }
        
        public Object getValue(String key) {
            if ("valueIcon".equals(key)) {
                return new ValueIcon();
            } else {
                return super.getValue(key);
            }
        }
    }
    
    public class ExceptionProperty extends PropertySupport {
        private Object myValue = "Value";
        // Create new Property
        public ExceptionProperty(String name, boolean isWriteable) {
            super(name, Object.class, name, "", true, isWriteable);
        }
        // get property value
        public Object getValue() {
            return myValue;
        }
        // set property value
        public void setValue(Object value) throws IllegalArgumentException,IllegalAccessException, InvocationTargetException {
            Object oldVal = myValue;
            myValue = value;
            tn.fireMethod(getName(), oldVal, myValue);
        }
        // get the property editor
        public PropertyEditor getPropertyEditor() {
            return exed;
        }
    }
    
    private ExEditor exed = new ExEditor();
    public static class ExEditor extends PropertyEditorSupport {
        private Object myVal="Value";
        public ExEditor() {}
        public void setAsText(String val) {
           //System.err.println("SetAsText");
            if (val.equals("Value") || val.equals("VALUE")) {
                myVal = val;
            } else {
                IllegalArgumentException iae = new IllegalArgumentException ("No!");
                ErrorManager.getDefault().annotate(iae, ErrorManager.USER, "NoNo!", "Localized message",null, null);
                throw iae;
            }
        }
        
        public void setValue(Object newValue) {
            myVal = newValue;
            firePropertyChange();
        }
        
        public Object getValue() {
            return "Value";
        }
    }
    
    
    // Editor definition
    public class EditorCustom extends PropertyEditorSupport implements ExPropertyEditor {
        PropertyEnv env;
        
        // Create new BasicEditor
        public EditorCustom() {
        }
        
        /*
         * This method is called by the IDE to pass
         * the environment to the property editor.
         */
        public void attachEnv(PropertyEnv env) {
            this.env = env;
            if ("Value".equals(getValue()) || "VALUE".equals(getValue())) {
                env.setState(env.STATE_INVALID);
            } else {
                env.setState(env.STATE_VALID);
            }
        }
        
        // Set that this Editor doesn't support custom Editor
        public boolean supportsCustomEditor() {
            return true;
        }
        
        // Set the Property value threw the Editor
        public void setValue(Object newValue) {
            super.setValue(newValue);
        }
        
        public String getAsText() {
            return getValue() == null ? "null" : getValue().toString();
        }
        
        public Component getCustomEditor() {
            JLabel result = new JLabel("Everything is exactly as it should be.  Relax.");
            result.putClientProperty("title","Don't panic");
            return result;
        }
        
        public void setAsText(String s) {
            super.setValue(s);
            if (!"Value".equals(s) && !"VALUE".equals(s)) {
                env.setState(env.STATE_VALID);
            } else {
                env.setState(env.STATE_INVALID);
            }
        }
    }
    
    public class NumProperty extends PropertySupport {
        private Integer myValue = new Integer(4);
        // Create new Property
        public NumProperty(String name, boolean isWriteable) {
            super(name, Integer.class, name, "", true, isWriteable);
        }
        // get property value
        public Object getValue() {
            return myValue;
        }
        // set property value
        public void setValue(Object value) throws IllegalArgumentException,IllegalAccessException, InvocationTargetException {
            if (!(value instanceof Integer)) {
                throw new IllegalArgumentException("Not an integer - " + value);
            }
            Object oldVal = myValue;
            myValue = (Integer) value;
            tn.fireMethod(getName(), oldVal, myValue);
        }
        // get the property editor
        public PropertyEditor getPropertyEditor() {
            return new NumberedTagsEditor();
        }
    }
    
    public class EditableNumProperty extends TagsProperty {
        public EditableNumProperty(String name, boolean isWriteable) {
            super (name, isWriteable, new String[]{"boo"});
        }

        public PropertyEditor getPropertyEditor() {
            return new EditableDisplayerTest.EditableTagsEditor();
        }
    }
    
    
    // Combo must display text, not numbers
    public class NumberedTagsEditor extends PropertyEditorSupport {
        private int val=3;
        // Create new BasicEditor
        public NumberedTagsEditor() {
        }
        
        public String[] getTags() {
            return new String[] {"zero","one","two","three","four","five","six","seven"};
        }

               
        // Set the Property value threw the Editor
        public void setValue(Object newValue) {
            val = ((Integer) newValue).intValue();
            firePropertyChange();
        }
        
        public String getAsText() {
            return getTags()[((Integer) getValue()).intValue()];
        }
        
        public void setAsText(String txt) {
            String[] t = getTags();
            for (int i=0; i < t.length; i++) {
                if (txt.trim().equals(t[i])) {
                    setValue(new Integer(i));
                    return;
                }
            }
            IllegalArgumentException iae = new IllegalArgumentException(txt);
            ErrorManager.getDefault().annotate(iae, ErrorManager.USER, txt, txt + " is not a valid value", null, null);
        }
        
        public Object getValue() {
            return new Integer(val);
        }
        
        public Component getCustomEditor() {
            return new JPanel();
        }
    }
    
    public class EditableTagsEditor extends TagsEditor implements ExPropertyEditor {
        private Object val="woof";
        public EditableTagsEditor() {
            super (new String[] {"miaou","woof","moo","quack"});
        }
        public void attachEnv (PropertyEnv env) {
            env.getFeatureDescriptor().setValue("canEditAsText", Boolean.TRUE);
        }
        public void setAsText(String s) {
            setValue(s);
        }
        public void setValue(Object val) {
            this.val = val;
        }
        public Object getValue() {
            return val;
        }
        public String getAsText() {
            return val.toString();
        }
        public boolean supportsCustomEditor() {
            return true;
        }
        public Component getCustomEditor() {
            return new JLabel("You called?");
        }
    }
    
    private class ValueIcon implements Icon {
        
        public int getIconHeight() {
            return 12;
        }
        
        public int getIconWidth() {
            return 12;
        }
        
        public void paintIcon(Component c, Graphics g, int x, int y) {
            Color col = g.getColor();
            try {
                g.setColor(Color.BLUE);
                g.drawRect(x, y, getIconWidth(), getIconHeight());
                g.fillRect(x+3, y+3, getIconWidth()-5, getIconHeight()-5);
            } finally {
                g.setColor(col);
            }
        }
    }    
    

    // Property definition
    public class StringProperty extends PropertySupport {
        private String myValue = "my oh my";
        // Create new Property
        public StringProperty(String name, boolean isWriteable) {
            super(name, String.class, name, "", true, isWriteable);
        }
        // get property value
        public Object getValue() {
            return myValue;
        }
        // set property value
        public void setValue(Object value) throws IllegalArgumentException,IllegalAccessException, InvocationTargetException {
            System.err.println("SETVALUE ON STRINGPROPERTY: " + value);
            Object oldVal = myValue;
            myValue = value.toString();
            tn.fireMethod(getName(), oldVal, myValue);
        }
    }    
    
    //Shamelessly stolen from util.IconManager
    private static final BufferedImage toBufferedImage(Image img) {
        // load the image
        new javax.swing.ImageIcon(img);
        java.awt.image.BufferedImage rep = createBufferedImage(img.getWidth(null), img.getHeight(null));
        java.awt.Graphics g = rep.createGraphics();
        g.drawImage(img, 0, 0, null);
        g.dispose();
        img.flush();
        return rep;
    }
    
    /** Creates BufferedImage 16x16 and Transparency.BITMASK */
    private static final java.awt.image.BufferedImage createBufferedImage(int width, int height) {
        java.awt.image.ColorModel model = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().
                                          getDefaultScreenDevice().getDefaultConfiguration().getColorModel(java.awt.Transparency.BITMASK);
        java.awt.image.BufferedImage buffImage = new java.awt.image.BufferedImage(model,
                model.createCompatibleWritableRaster(width, height), model.isAlphaPremultiplied(), null);
        return buffImage;
    }
    

    
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.