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.BorderLayout;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
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 javax.swing.text.JTextComponent;
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.beans.PropertyVetoException;
import java.io.File;
import java.lang.ref.WeakReference;
import java.lang.reflect.*;
import javax.swing.*;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import junit.framework.*;
import junit.textui.TestRunner;
import org.netbeans.junit.*;
import org.openide.ErrorManager;
import org.openide.util.Lookup;

/* A comprehensive test of PropertyPanel */
public class NewPropertyPanelTest extends NbTestCase {
    
    static {
        org.netbeans.core.NonGui.registerPropertyEditors();
    }
    
    public NewPropertyPanelTest(String name) {
        super(name);
    }
    
    public static void main(String args[]) {
//        LookAndFeel lf = UIManager.getLookAndFeel();
/*        try {
            UIManager.setLookAndFeel(new com.jgoodies.plaf.plastic.Plastic3DLookAndFeel());
        } catch (Exception e) {
            e.printStackTrace();
        }
 */
        
        
        TestRunner.run(suite ());
        
        
        /*
        boolean go=false;
        try {
            UIManager.setLookAndFeel(new PseudoWindowsLookAndFeel());
            go = true;
        } catch (NoClassDefFoundError e) {
            System.err.println("Couldn't run tests on windows look and feel");
        } catch (UnsupportedLookAndFeelException e) {
            System.err.println("Couldn't run tests on windows look and feel");
        }            
        if (go) {
            TestRunner.run(suite ());
        }
        go=false;
        try {
            UIManager.setLookAndFeel(new com.sun.java.swing.plaf.gtk.GTKLookAndFeel());
            go = true;
        } catch (NoClassDefFoundError e) {
            System.err.println("Couldn't run tests on GTK look and feel");
            e.printStackTrace();
        } catch (UnsupportedLookAndFeelException e) {
            System.err.println("Couldn't run tests on GTK look and feel");
            e.printStackTrace();
        }
        if (go) {
            TestRunner.run(suite ());
        }
        try {
            UIManager.setLookAndFeel(lf);
        } catch (Exception e) {
            //highly unlikely 
        }
         */
        try {
//        new NewPropertyPanelTest("goo").setUp();
        } catch (Exception e){}
 
    }

    static int idx = -1;
    public static Test suite() {
        return new CustomEditorDisplayerSuite ();
    }
    
    private static class CustomEditorDisplayerSuite extends NbTestSuite {
        public CustomEditorDisplayerSuite () {
            super (NewPropertyPanelTest.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.
 */
   
    private JButton focusButton;
    PropertyPanel customPanel;
    PropertyPanel filePanel;
    PropertyPanel tagsPanel;
    PropertyPanel stringPanel;
    
    private TNode tn;
    private BasicProperty basicProp;
    private FileProperty fileProp;
    private BasicEditor te;
    private TagsProperty tagsProp;
    private StringProperty stringProp;
    
    private boolean setup=false;
    private JFrame jf=null;
    private JPanel jp=null;
    private int SLEEP_LENGTH=10; //Make this longer to see what the test is doing
    
    protected void tearDown() {
        if (jf != null) {
//            jf.hide();
//            jf.dispose();
        }
    }
   
    protected void setUp() throws Exception {
        PropUtils.forceRadioButtons=false;
        
        
        try {
            if (setup) return;
            basicProp= new BasicProperty("basicProp", true);
            fileProp= new FileProperty("FileProp", true);
            tagsProp = new TagsProperty("TagsProp", true);
            stringProp = new StringProperty("StringProp", true);
            
            focusButton = new JButton("Somewhere over the rainbow");
            // 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, 600);

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

                customPanel = new PropertyPanel(basicProp);
                filePanel = new PropertyPanel(fileProp);
                tagsPanel = new PropertyPanel(tagsProp);
                stringPanel = new PropertyPanel(stringProp);
                
                tagsPanel.setBackground(Color.GREEN);
                
                filePanel.setBackground(Color.YELLOW);
                
                stringPanel.setBackground(Color.PINK);

                customPanel.setPreferences(PropertyPanel.PREF_CUSTOM_EDITOR);
                
                filePanel.setPreferences(PropertyPanel.PREF_CUSTOM_EDITOR);
                
                jp.add(customPanel);
                
                jp.add(filePanel);
                
                jp.add (focusButton);
                
                jp.add (stringPanel);
                
                jp.add (tagsPanel);
            }

            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 testReadOnlyMode() throws Exception {
        requestFocus (focusButton);
        changeProperty (stringPanel, stringProp);
        setPreferences(stringPanel, PropertyPanel.PREF_READ_ONLY | PropertyPanel.PREF_INPUT_STATE);
        Component owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
        
        requestFocus(stringPanel);
        Component owner2 = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
        
        assertSame("Requesting focus on a read only inline editor panel should not change the focus owner, but it was " + owner2, owner, owner2);

        requestFocus(stringPanel);
        setPreferences(filePanel, PropertyPanel.PREF_READ_ONLY | PropertyPanel.PREF_CUSTOM_EDITOR);
        jf.repaint();
        Component owner3 = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
        
        assertSame("Requesting focus on a read only custom editor panel should not change the focus owner, not " + owner3, owner, owner3);
    }
    
    
    public void testEnabled() throws Exception {
        requestFocus (focusButton);
        sleep();
        changeProperty (filePanel, fileProp);
        sleep();
        setEnabled (filePanel, false);
        sleep();
        Component owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
        
        requestFocus(filePanel);
        Component owner2 = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
        
        assertSame("Requesting focus on a disabled inline editor panel should not change the focus owner, but it was " + owner2, owner, owner2);
        
        setPreferences(filePanel, PropertyPanel.PREF_CUSTOM_EDITOR);
        
        requestFocus(filePanel);
        Component owner3 = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
        
        assertSame("Requesting focus on a disabled custom editor panel should not change the focus owner, not " + owner3, owner, owner3);

        setPreferences(filePanel, PropertyPanel.PREF_INPUT_STATE);
    
        Component owner4 = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
        
        assertSame("Changing preferences on a property panel should not enable it to be focused if it is disabled" + owner4, owner, owner4);
        
        setEnabled(filePanel, true);
        
        requestFocus(filePanel);
        
        Component owner5 = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
        assertNotSame("Setting enabled to true should restore focusability", owner5, owner);
        assertTrue("Setting enabled to true and requesting focus should set focus to a child of the panel", filePanel.isAncestorOf(owner5));
        
        requestFocus(focusButton);
        owner5 = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
        //XXX better to do this for JFileChooser, but it has bugs - it *is* still focusable
        
        changeProperty(filePanel, stringProp);
        setEnabled(filePanel, false);
        requestFocus(focusButton);
        owner5 = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
        
        setPreferences(filePanel, PropertyPanel.PREF_CUSTOM_EDITOR);
        requestFocus(focusButton);
        jp.repaint();
        sleep();
        
        requestFocus(filePanel);
        Component owner6 = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
        
        assertTrue("Setting focus on a disabled custom editor component should neither set focus to it nor its children, but focus is on " + owner6,
            owner6 != filePanel && !filePanel.isAncestorOf(owner6));
    }
     

    public void testChangingPreferences() throws Exception {
        Dimension d = filePanel.getPreferredSize();
        requestFocus(filePanel);
        sleep();
        Component owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
        
        assertTrue ("After requesting focus on an enabled property panel containing a file custom editor, focus should be on some child of the property panel, but it is " + owner,
            filePanel.isAncestorOf(owner));
        
        sleep();
        
        setPreferences(filePanel, PropertyPanel.PREF_INPUT_STATE);
        jf.validate();
        jf.repaint();
        Dimension d2 = filePanel.getPreferredSize();
        assertTrue ("Panel returned same preferred size in inline and custom editor mode.  Probably the inner component wasn't changed when the preferences were changed.",
            !d.equals(d2));
        sleep();
        
        Component newOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
        assertTrue ("After changing preferences from custom editor to non-custom editor in a displayed property panel, focus owner should still be in panel, but it is " + newOwner,
            filePanel.isAncestorOf(newOwner));
    }
    
    
    public void testPropertyPanelSendsFocusLost() throws Exception {
        //This test is in referenced to a filed issue that the old property
        //panel did not send focus lost events properly
        
        requestFocus(focusButton);
        FL fliFile = new FL();
        FL fliBasic = new FL();
        filePanel.addFocusListener(fliFile);
        customPanel.addFocusListener(fliBasic);
        
        requestFocus(filePanel);
        fliFile.assertGained("Setting focus to a custom editor did not generate a focus gained event");
        
        requestFocus(customPanel);
        fliFile.assertLost("Setting focus from one custom editor to another did not generate a focus lost event from the first one");
        
        fliBasic.assertGained("Setting focus to a custom editor from another did not generate a focus gained event from the second one");

        requestFocus(focusButton);
        fliBasic.assertLost("Setting focus to a non property panel component did not generate a focus lost event");
        
        setPreferences (filePanel, PropertyPanel.PREF_INPUT_STATE);
        
        requestFocus(filePanel);
        fliFile.assertGained("Setting focus to a property panel displaying an inline editor from a non-property panel component did not generate a focus gained event");
        
        requestFocus(focusButton);
        fliFile.assertLost("Setting focus away from a property panel displaying an inline editor to a non-property panel component did not generate a focus lost event");
    }
    
    public void testTableUIBehavior () throws Exception {
        requestFocus (tagsPanel);
        
        System.err.println("TAGS PANEL BOUNDS: " + tagsPanel.getBounds());
        
        Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
        assertTrue ("After requesting focus on a property with tags, a combo box should have focus, not " + focusOwner,
            focusOwner instanceof JComboBox);
        
        assertTrue("After requesting focus on a property with tags, with TableUI false, the combo's popup should not be open",
            !((JComboBox) focusOwner).isPopupVisible());
        
        requestFocus(focusButton);
        
        tagsPanel.setPreferences(PropertyPanel.PREF_TABLEUI);
        
        requestFocus(tagsPanel);
        focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
        
        assertTrue ("After requesting focus on a property with tags, a combo box should have focus, not " + focusOwner,
            focusOwner instanceof JComboBox);
        
        assertTrue("After requesting focus on a property with tags, with TableUI true, the combo's popup should be open",
            ((JComboBox) focusOwner).isPopupVisible());
        
        sleep();
        requestFocus(focusButton);

        /*
        //Commenting this out for now - too heavily depends to on the look and
        //feel's behavior
        assertTrue("After shifting focus away from a tableUI combo box, its popup should no longer be open",
            !((JComboBox) focusOwner).isPopupVisible());
         */
        
    }
    
    
    public void testClientProperties() throws Exception {
        tagsPanel.putClientProperty("radioButtonMax", new Integer(100));
        sleep();
        sleep();
        requestFocus(tagsPanel);
        Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();

        assertTrue ("After setting focus to a panel for a property editor with tags below the radio button threshold, focus should be on a radio button, but was " + focusOwner,
            focusOwner instanceof JRadioButton);
        
        requestFocus (focusButton);
        
        tagsPanel.putClientProperty("radioButtonMax", null);
        sleep();
        sleep();
        requestFocus(tagsPanel);
        Component focusOwner2 = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
        
        assertNotSame("Focus owner should not be same as previous if the value of radioButtonMax has changed significantly",
            focusOwner, focusOwner2);
        
        assertTrue("After resetting radioButtonMax client property and requesting focus, a radio button should not be what gets focus on requestFocus",
            (!(focusOwner2 instanceof JRadioButton)));
        
        assertTrue("After resetting radioButtonMax client property and requesting focus, a combo box should be what gets focus on requestFocus",
            focusOwner2 instanceof JComboBox);

        requestFocus (focusButton);
        
        tagsPanel.putClientProperty("radioButtonMax", new Integer(100));
        sleep();
        tagsPanel.putClientProperty("useLabels", Boolean.TRUE);
        
        sleep();
        
    }
       
    public void testReplaceProperty() throws Exception {
        Node.Property p = stringPanel.getProperty();
        requestFocus(stringPanel);
        typeKey(stringPanel, KeyEvent.VK_W);
        typeKey(stringPanel, KeyEvent.VK_H);
        typeKey(stringPanel, KeyEvent.VK_O);
        typeKey(stringPanel, KeyEvent.VK_A);

        changeProperty(stringPanel, tagsProp);
        
        Node.Property p2 = stringPanel.getProperty();
        
        assertNotSame("After replacing the property, it should not be the former one", 
            p2, p);

        setPreferences(stringPanel, PropertyPanel.PREF_CUSTOM_EDITOR);
        
        changeProperty(stringPanel, fileProp);
        
        PCL pcl = new PCL();
        stringPanel.addPropertyChangeListener(pcl);
        
        //Set the value in a way that will trigger an env property change
        //on a property the panel should no longer be listening to
        tagsProp.getPropertyEditor().setAsText("c"); //will be an invalid value
        
        pcl.assertNoEvent("Change in a property editor not related to the current property in a propertypanel whose property was changed nonetheless triggered a state changed event from the panel");
        
        filePanel.setPreferences(PropertyPanel.PREF_CUSTOM_EDITOR);
        requestFocus(filePanel);
        Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();

        changeProperty (filePanel, stringProp);
        requestFocus(filePanel);
        
        Component focusOwner2 = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
        
        assertNotSame("After changing the property in a custom editor panel to one with different property type, the component focus gets set to on a call to requestFocus should not be the same type as before",
            focusOwner.getClass(), focusOwner2.getClass());
    }

    public void testWriteValues() throws Exception {
        stringPanel.setChangeImmediate(false);
        assertTrue ("Panel contains the wrong property: " + stringPanel.getProperty(), stringPanel.getProperty() == stringProp);
        
        requestFocus(stringPanel);
        Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
        assertTrue ("Requesting focus on a property panel for a string property should set focus to a JTextField not " + focusOwner,
            focusOwner instanceof JTextComponent);
        
        typeKey(stringPanel, KeyEvent.VK_T);
        typeKey(stringPanel, KeyEvent.VK_H);
        typeKey(stringPanel, KeyEvent.VK_E);
        typeKey(stringPanel, KeyEvent.VK_R);
        typeKey(stringPanel, KeyEvent.VK_E);
        typeKey(stringPanel, KeyEvent.VK_S);
        typeKey(stringPanel, KeyEvent.VK_SPACE);
        typeKey(stringPanel, KeyEvent.VK_A);
        
        Object o = stringPanel.getProperty().getValue();
        assertTrue ("After typing into  a property panel string editor, property value should not be what was typed",
            !o.equals("THERES A"));
        
        //pressKey(focusOwner, KeyEvent.VK_ENTER);
        stringPanel.updateValue();
        Object o2 = stringPanel.getProperty().getValue();

        assertNotSame(o,o2);
        assertTrue ("After typing into a property panel string editor and pressing enter, property value should be what was typed, but it was <" + o + ">",
            o2.equals("THERES A"));
    }
    
    
    public void testMarkingUpdates() throws Exception {
        requestFocus(tagsPanel);
        sleep();
        
        InplaceEditor outer = ((EditablePropertyDisplayer) tagsPanel.inner).getInplaceEditor();
        assertTrue ("Should be a button panel for component supporting a custom editor", outer instanceof ButtonPanel);
        assertTrue ("Button panel should contain a combo box", ((ButtonPanel) outer).getInplaceEditor() instanceof ComboInplaceEditor);
        
        sleep();
        sleep();
        pressKey(tagsPanel, KeyEvent.VK_DOWN);
        pressKey(tagsPanel, KeyEvent.VK_UP);
        pressKey(tagsPanel, KeyEvent.VK_UP);

        InplaceEditor newOuter = ((EditablePropertyDisplayer) tagsPanel.inner).getInplaceEditor();
//        assertTrue ("After setting an illegal value, the outer component should be an IconPanel to show the illegal value mark, not " + newOuter,
//            newOuter instanceof IconPanel);
        
        
        pressKey(tagsPanel, KeyEvent.VK_UP);

        sleep();
        sleep();
        newOuter = ((EditablePropertyDisplayer) tagsPanel.inner).getInplaceEditor();
        sleep();
        assertTrue ("After setting a legal value, the outer component should be an IconPanel to show the illegal value mark, but it is " + newOuter,
            newOuter instanceof ButtonPanel);
    }
    
    public void testSuppressEditorButton () throws Exception {
        requestFocus (tagsPanel);
        InplaceEditor outer = ((EditablePropertyDisplayer) tagsPanel.inner).getInplaceEditor();
        assertTrue ("Should be a button panel for component supporting a custom editor", outer instanceof ButtonPanel);
        
        tagsPanel.putClientProperty("suppressCustomEditor", Boolean.TRUE);
        sleep();
        sleep();
        sleep();
        
        outer = ((EditablePropertyDisplayer) tagsPanel.inner).getInplaceEditor();
        
        assertTrue ("Should be no button panel when suppressing custom editor", !(outer instanceof ButtonPanel));
    }
    
    
    private class PCL implements PropertyChangeListener {
        private PropertyChangeEvent event;
        
        public void assertNoEvent (String msg) {
            assertNull(msg, event);
        }
        
        public void assertEvent (String msg) {
            PropertyChangeEvent pce = event;
            event = null;
            assertNotNull(msg, event);
        }
        
        public void propertyChange(PropertyChangeEvent evt) {
            
        }
        
    }
    
    
    private void setPreferences (final PropertyPanel pp, final int preferences) throws Exception {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                throwMe = null;
                try {
                    pp.setPreferences(preferences);
                } catch (Exception e) {
                    throwMe = e;
                }
            }
        });
        if (throwMe != null) {
            Exception e = throwMe;
            throwMe = null;
            throw e;
        } else {
            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(String msg) {
            int currGainedCount = gainedCount;
            gainedCount = 0;
            FocusEvent gained = gainedEvent;
            gainedEvent = null;
            assertNotNull (msg, gained);
            assertTrue("Received wrong number of focus gained events for a single click on a renderer " +  currGainedCount, currGainedCount == 1);
        }
        
        public void assertLost(String msg) {
            int currLostCount = lostCount;
            lostCount = 0;
            FocusEvent lost = lostEvent;
            lostEvent = null;
            assertNotNull (msg, lost);
            assertTrue("Received wrong number of focus lost events for a single click away from a focused renderer" + currLostCount, currLostCount == 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();
            f.toFront();
            f.requestFocus();
            if (!shown) {
                synchronized(this) {
                    try {
                        //System.err.println("Waiting for window");
                            wait(6000);
                    } catch (Exception e) {}
                }
            }
            int ct = 0;
            while (!f.isShowing()) {
                ct++;
                try {
                    Thread.currentThread().sleep(400);
                } catch (Exception e) {
                    
                }
                if (ct > 100) {
                    break;
                }
            }
            ct=0;
            Container c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow();
            while (c != f) {
                try {
                    Thread.currentThread().sleep(400);
                } catch (Exception e) {
                    
                }
                c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow();
                ct++;
                if (ct > 100) {
                    break;
                }
            }
        }
        
        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
        }
         
        
         
        //runs faster -uncomment for production use
        
        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 void requestFocus(final JComponent jc) throws Exception {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                jc.requestFocus();
            }
        });
        sleep();
    }
    
    private void changeProperty (final PropertyPanel ren, final Node.Property newProp) throws Exception {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                ren.setProperty(newProp);
            }
        });
    }
    
    private void clickOn (final JComponent 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);
                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 JComponent ren) throws Exception {
        SwingUtilities.invokeAndWait (new Runnable() {
            public void run() {
                Point toClick = new Point(5,5);
                Component target=ren.getComponentAt(toClick);
                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 PropertyPanel 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 PropertyPanel 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 Exception throwMe2 = null;
    private void pressKey (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(), 0, key, (char) key);
                try {
                    target.dispatchEvent(ke);
                } catch (Exception e) {
                    throwMe2 = e;
                }
            }
        });
        sleep();
        if (throwMe2 != null) {
            Exception e1 = throwMe2;
            throwMe2 = null;
            throw e1;
        }
    }
    
    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 typeKey (final Component target, final int key) throws Exception {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                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(fileProp);
            
            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 {
            System.err.println("BASICPROP setValue to " + value + " (was " + myValue+")");
            Object oldVal = myValue;
            myValue = value;
            tn.fireMethod(getName(), oldVal, myValue);
        }
        // get the property editor
        public PropertyEditor getPropertyEditor() {
            return te;
        }
    }

    // Property definition
    public class FileProperty extends PropertySupport {
        private Object myValue = new File("aFile");
        // Create new Property
        public FileProperty(String name, boolean isWriteable) {
            super(name, File.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);
        }
    }

    // Property definition
    public class TagsProperty extends PropertySupport {
        private Object myValue = "Value";
        // Create new Property
        public TagsProperty(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
        PropertyEditor editor = null;
        public PropertyEditor getPropertyEditor() {
            if (editor == null) {
                editor = new TagsEditor();
            }
            return editor;
        }
    }
    
    // Property definition
    public class StringProperty extends PropertySupport {
        private Object myValue = "way up high";
        // 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;
            tn.fireMethod(getName(), oldVal, myValue);
        }
    }    
    
    
    public class TagsEditor extends PropertyEditorSupport implements ExPropertyEditor {
        PropertyEnv env;
        
        public TagsEditor() {
        }
        
        public String[] getTags() {
            return new String[] {"a","b","c","d","Value"};
        }
        
        public void attachEnv(PropertyEnv env) {
            this.env = env;
            if ("c".equals(getValue())) {
                env.setState(env.STATE_INVALID);
            } else {
                env.setState(env.STATE_VALID);
            }
        }
        
        public boolean supportsCustomEditor() {
            return true;
        }
        
        public Component getCustomEditor() {
            return new JColorChooser();
        }
        
        public void setValue(Object newValue) {
            super.setValue(newValue);
            if (env != null) {
                if ("c".equals(newValue)) {
                    env.setState(env.STATE_INVALID);
                } else {
                    env.setState(env.STATE_NEEDS_VALIDATION);
                }
            }
        }
    }
    
    // Editor definition
    public class BasicEditor extends PropertyEditorSupport implements ExPropertyEditor, PropertyChangeListener, VetoableChangeListener {
        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) {
            if (env != null) {
                env.removeVetoableChangeListener(this);
            }
            this.env = env;
            
            env.setState(env.STATE_VALID);
            env.addVetoableChangeListener(this);
            System.err.println("  ATTACHENV");
            
        }
        
        // 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) {
            System.err.println(" BasicEditor.setValue: " + newValue);
            super.setValue(newValue);
        }
        
        public String getAsText() {
            return getValue() == null ? "null" : getValue().toString();
        }

        private Component custom;
        public Component getCustomEditor() {
            if (custom == null) {
                custom = new BasicCustomEditor(this);
            }
            return custom;
        }
        
        public void vetoNext() {
            env.setState(env.STATE_NEEDS_VALIDATION);
            vetoNextChange = true;
            System.err.println(" veto next");
        }
        
        public void propertyChange(PropertyChangeEvent evt) {
            
        }
        
        boolean vetoNextChange=false;
        public void vetoableChange(PropertyChangeEvent e) throws PropertyVetoException {
            System.err.println("GOT A VETOABLE CHANGE IN BASIC EDITOR");
            PropertyEnv env = (PropertyEnv) e.getSource();
            if ((vetoNextChange || "Dont allow validate".equals(getAsText())) && PropertyEnv.STATE_NEEDS_VALIDATION.equals(env.getState())) {
                System.err.println(" VETOING");
                PropertyVetoException pve = new PropertyVetoException("NoNoNoNoNo", e);
                ErrorManager.getDefault().annotate(pve, ErrorManager.USER, null, "You can't do that!", null, null);
                vetoNextChange=false;
                throw pve;
            }
        }
        
        public void setAsText(String s) {
            System.err.println(" BasicEditor.setAsText: " + s);
            if ("invalidValue".equals(s)) {
                IllegalArgumentException iae = new IllegalArgumentException();
                ErrorManager.getDefault().annotate(iae, ErrorManager.USER, "invalid value", "No way", null, null);
                throw iae;
            }
            setValue(s);
        }
        
    }
    
    
    public class BasicCustomEditor extends JPanel implements ActionListener {
        JTextField valueField=new JTextField();
        JButton setInvalidValueButton = new JButton("Invalid value");
        JButton setDontAllowValidateButton = new JButton("Dont allow validate");
        BasicEditor editor;
        public BasicCustomEditor(BasicEditor editor) {
            this.editor = editor;
            init();
        }
        
        private void init() {
            setLayout(new FlowLayout());
            valueField.addActionListener(this);
            setInvalidValueButton.addActionListener(this);
            setDontAllowValidateButton.addActionListener(this);
            valueField.setColumns(30);
            setBackground(Color.ORANGE);
            add (valueField);
            add (setInvalidValueButton);
            add (setDontAllowValidateButton);
        }
        boolean processing;
        public void actionPerformed(ActionEvent e) {
            processing = true;
            try {
                if (e.getSource() == setDontAllowValidateButton) {
                    editor.vetoNext();
                    valueField.setText("dont allow validate");
                }
                if (e.getSource() == setInvalidValueButton) {
                    valueField.setText("invalidValue");
                }
                if (e.getSource() == valueField) {
                    editor.setAsText(valueField.getText());
                }
                editor.env.setState(PropertyEnv.STATE_NEEDS_VALIDATION);
            } finally {
                processing = false;
            }
        }
    }
}
... 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.