Revision: 1112
Author: re...@colorado.edu
Date: Mon Mar  7 11:50:37 2011
Log: Applied fixes from the piccolo 1.3 branch to trunk, see issue 163
http://code.google.com/p/piccolo2d/source/detail?r=1112

Added:
/piccolo2d.java/trunk/extras/src/test/java/org/piccolo2d/extras/pswing/PSwingDynamicComponentExample.java
Modified:
/piccolo2d.java/trunk/extras/src/main/java/org/piccolo2d/extras/pswing/PSwing.java /piccolo2d.java/trunk/extras/src/main/java/org/piccolo2d/extras/pswing/PSwingRepaintManager.java

=======================================
--- /dev/null
+++ /piccolo2d.java/trunk/extras/src/test/java/org/piccolo2d/extras/pswing/PSwingDynamicComponentExample.java Mon Mar 7 11:50:37 2011
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2008-2010, Piccolo2D project, http://piccolo2d.org
+ * Copyright (c) 1998-2008, University of Maryland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its + * contributors may be used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.piccolo2d.extras.pswing;
+
+import javax.swing.*;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.LineBorder;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Demonstrates a PSwing problem with dynamic JComponents.
+ * <p>
+ * This example shows 2 identical JPanels.
+ * The panel on the left uses PSwing.
+ * The panel on the right uses pure Swing.
+ * <p>
+ * The JPanel contain various JComponents whose text can be updated by
+ * typing into JTextFields and pressing the "Update" button.
+ * The JPanel managed by PSwing is often rendered incorrectly.
+ * <p>
+ * Please see piccolo2d issue 163 for more information about this problem and solution:
+ * http://code.google.com/p/piccolo2d/issues/detail?id=163
+ *
+ * @author Chris Malley (cmal...@pixelzoom.com)
+ * @author Sam Reid
+ */
+public class PSwingDynamicComponentExample extends JFrame {
+
+    private static final Dimension FRAME_SIZE = new Dimension( 800, 400 );
+    private static final int TEXT_FIELD_COLUMNS = 30;
+
+    private final ComponentPanel swingPanel, piccoloPanel;
+ private final JTextField labelTextField, checkBoxTextField, radioButtonTextField;
+
+    public PSwingDynamicComponentExample() {
+        super( PSwingDynamicComponentExample.class.getName() );
+        setSize( FRAME_SIZE );
+
+        // canvas
+        PSwingCanvas canvas = new PSwingCanvas();
+        canvas.setBackground( Color.RED );
+        canvas.removeInputEventListener( canvas.getZoomEventHandler() );
+        canvas.removeInputEventListener( canvas.getPanEventHandler() );
+
+        // panel that we'll display using Piccolo
+        piccoloPanel = new ComponentPanel();
+        final PSwing pswing = new PSwing( piccoloPanel );
+        canvas.getLayer().addChild( pswing );
+        pswing.setOffset( 10, 10 );
+
+        // panel that we're display using pure Swing
+        swingPanel = new ComponentPanel();
+        JPanel jpanel = new JPanel();
+        jpanel.setBorder( new LineBorder( Color.BLACK ) );
+        jpanel.add( swingPanel );
+
+        // text fields, for specifying dynamic text
+ labelTextField = new JTextField( swingPanel.label.getText(), TEXT_FIELD_COLUMNS ); + checkBoxTextField = new JTextField( swingPanel.checkBox.getText(), TEXT_FIELD_COLUMNS ); + radioButtonTextField = new JTextField( swingPanel.radioButton.getText(), TEXT_FIELD_COLUMNS );
+
+        // Update button, for applying dynamic text
+        JButton updateButton = new JButton( "Update" );
+        updateButton.addActionListener( new ActionListener() {
+            public void actionPerformed( ActionEvent e ) {
+                updatePanels();
+            }
+        } );
+
+        //
+        JButton addComponentButton = new JButton( "add component" );
+        addComponentButton.addActionListener( new ActionListener() {
+
+            public void actionPerformed( ActionEvent e ) {
+                piccoloPanel.addComponent( new JLabel( "new" ) );
+                swingPanel.addComponent( new JLabel( "new" ) );
+            }
+
+        });
+
+        // control panel
+        JPanel controlPanel = new JPanel();
+        controlPanel.setBorder( new LineBorder( Color.BLACK ) );
+        controlPanel.setLayout( new GridBagLayout() );
+        GridBagConstraints c = new GridBagConstraints();
+        // JLabel
+        c.gridx = 0;
+        c.gridy = 0;
+        c.anchor = GridBagConstraints.EAST;
+        controlPanel.add( new JLabel( "JLabel text:" ), c );
+        c.gridx++;
+        c.anchor = GridBagConstraints.WEST;
+        controlPanel.add( labelTextField, c );
+        // JCheckBox
+        c.gridx = 0;
+        c.gridy++;
+        c.anchor = GridBagConstraints.EAST;
+        controlPanel.add( new JLabel( "JCheckBox text:" ), c );
+        c.gridx++;
+        c.anchor = GridBagConstraints.WEST;
+        controlPanel.add( checkBoxTextField, c );
+        // JRadioButton
+        c.gridx = 0;
+        c.gridy++;
+        c.anchor = GridBagConstraints.EAST;
+        controlPanel.add( new JLabel( "JRadioButton text:" ), c );
+        c.gridx++;
+        c.anchor = GridBagConstraints.WEST;
+        controlPanel.add( radioButtonTextField, c );
+        // Update button
+        c.gridx = 1;
+        c.gridy++;
+        c.anchor = GridBagConstraints.WEST;
+        controlPanel.add( updateButton, c );
+        // Add component buttons
+        c.gridx = 1;
+        c.gridy++;
+        c.anchor = GridBagConstraints.WEST;
+        controlPanel.add( addComponentButton, c );
+
+
+
+        // main panel
+        JPanel mainPanel = new JPanel( new BorderLayout() );
+        mainPanel.add( canvas, BorderLayout.CENTER );
+        mainPanel.add( jpanel, BorderLayout.EAST );
+        mainPanel.add( controlPanel, BorderLayout.SOUTH );
+        setContentPane( mainPanel );
+    }
+
+    // applies the text field values to the components in the panels
+    private void updatePanels() {
+
+        // Piccolo (PSwing) panel
+        piccoloPanel.label.setText( labelTextField.getText() );
+        piccoloPanel.checkBox.setText( checkBoxTextField.getText() );
+        piccoloPanel.radioButton.setText( radioButtonTextField.getText() );
+
+        // Swing panel
+        swingPanel.label.setText( labelTextField.getText() );
+        swingPanel.checkBox.setText( checkBoxTextField.getText() );
+        swingPanel.radioButton.setText( radioButtonTextField.getText() );
+    }
+
+    // A panel with a few different types of JComponent.
+    private static class ComponentPanel extends JPanel {
+
+        // allow public access to keep our example code short
+        public final JLabel label;
+        public final JCheckBox checkBox;
+        public final JRadioButton radioButton;
+        public final GridBagConstraints constraints;
+
+        public ComponentPanel() {
+ setBorder( new CompoundBorder( new LineBorder( Color.BLACK, 1 ), new EmptyBorder( 5, 14, 5, 14 ) ) );
+            setBackground( new Color( 180, 205, 255 ) );
+
+            // components
+            label = new JLabel( "JLabel" );
+            checkBox = new JCheckBox( "JCheckBox" );
+            radioButton = new JRadioButton( "JRadioButton" );
+
+            // layout
+            setLayout( new GridBagLayout() );
+            constraints = new GridBagConstraints();
+            constraints.anchor = GridBagConstraints.WEST;
+            constraints.gridx = 0;
+            constraints.gridy = GridBagConstraints.RELATIVE;
+            addComponent( label );
+            addComponent( checkBox );
+            addComponent( radioButton );
+        }
+
+        public void addComponent( JComponent c ) {
+            add( c, constraints );
+            revalidate();
+        }
+    }
+
+    public static class SleepThread extends Thread {
+
+        public SleepThread( long millis ) {
+            super( new Runnable() {
+                public void run() {
+                    while ( true ) {
+                        try {
+                            SwingUtilities.invokeAndWait( new Runnable() {
+                                public void run() {
+                                    try {
+                                        Thread.sleep( 1000 );
+                                    }
+                                    catch ( InterruptedException e ) {
+                                        e.printStackTrace();
+                                    }
+                                }
+                            } );
+                        }
+                        catch ( InterruptedException e ) {
+                            e.printStackTrace();
+                        }
+                        catch ( InvocationTargetException e ) {
+                            e.printStackTrace();
+                        }
+                    }
+                }
+            } );
+        }
+    }
+
+    public static void main( String[] args ) {
+        // This thread serves to make the problem more noticeable.
+//        new SleepThread( 1000 ).start();
+        SwingUtilities.invokeLater( new Runnable() {
+            public void run() {
+                JFrame frame = new PSwingDynamicComponentExample();
+ frame.setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );
+                frame.setVisible( true );
+            }
+        } );
+    }
+}
=======================================
--- /piccolo2d.java/trunk/extras/src/main/java/org/piccolo2d/extras/pswing/PSwing.java Mon May 10 20:10:56 2010 +++ /piccolo2d.java/trunk/extras/src/main/java/org/piccolo2d/extras/pswing/PSwing.java Mon Mar 7 11:50:37 2011
@@ -37,12 +37,9 @@
 import java.awt.RenderingHints;
 import java.awt.Shape;
 import java.awt.Stroke;
-import java.awt.event.ComponentAdapter;
-import java.awt.event.ComponentEvent;
 import java.awt.event.ContainerAdapter;
 import java.awt.event.ContainerEvent;
 import java.awt.event.ContainerListener;
-import java.awt.geom.Rectangle2D;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.io.IOException;
@@ -60,7 +57,6 @@
 import org.piccolo2d.util.PBounds;
 import org.piccolo2d.util.PPaintContext;

-
 /*
  This message was sent to Sun on August 27, 1999

@@ -192,6 +188,7 @@
  * </p>
  *
  * @author Sam R. Reid
+ * @author Chris Malley (cmal...@pixelzoom.com)
  * @author Benjamin B. Bederson
  * @author Lance E. Good
  *
@@ -220,7 +217,7 @@

     /**
* Default stroke, <code>new BasicStroke()</code>. Cannot be made static
-     * because BasicStroke is not serializable.
+     * because BasicStroke is not serializable.  Should not be null.
      */
     private Stroke defaultStroke = new BasicStroke();

@@ -271,12 +268,6 @@

     };

- private final PropertyChangeListener reshapeListener = new PropertyChangeListener() {
-        public void propertyChange(final PropertyChangeEvent evt) {
-            repaint();
-        }
-    };
-
     /**
* Listens to container nodes for changes to its contents. Any additions
      * will automatically have double buffering turned off.
@@ -296,9 +287,10 @@
* I'm assuming that the intent of the is method is that it should be * called explicitly by anyone making changes to the hierarchy of the
          * Swing component graph.
+ * @param targetComponent the component for which double buffering should be removed
          */
private void disableDoubleBuffering(final JComponent targetComponent) {
-            targetComponent.setDoubleBuffered(false);
+            targetComponent.setDoubleBuffered( false );
             for (int i = 0; i < targetComponent.getComponentCount(); i++) {
                 final Component c = targetComponent.getComponent(i);
                 if (c instanceof JComponent) {
@@ -319,41 +311,56 @@
         initializeComponent(component);

         component.revalidate();
- //TODO: this listener is suspicious, it's not listening for any specific property
-        component.addPropertyChangeListener(new PropertyChangeListener() {
-            /** {@inheritDoc} */
-            public void propertyChange(final PropertyChangeEvent evt) {
-                updateBounds();
-            }
-        });
-
         updateBounds();
         listenForCanvas(this);
     }
+
+    /**
+     * @deprecated by {@link #PSwing(JComponent)}
+     *
+     * @param swingCanvas canvas on which the PSwing node will be embedded
+     * @param component not used
+     */
+ public PSwing(final PSwingCanvas swingCanvas, final JComponent component) {
+        this(component);
+    }

     /**
* Ensures the bounds of the underlying component are accurate, and sets the
      * bounds of this PNode.
      */
     public void updateBounds() {
-        // Avoid setBounds if it is unnecessary
-        // TODO: should we make sure this is called at least once
- // TODO: does this sometimes need to be called when size already equals
-        // preferred size, to relayout/update things?
+        /*
+         * Need to explicitly set the component's bounds because
+ * the component's parent (PSwingCanvas.ChildWrapper) has no layout manager.
+         */
         if (componentNeedsResizing()) {
- component.setBounds(0, 0, component.getPreferredSize().width, component.getPreferredSize().height);
-        }
- setBounds(0, 0, component.getPreferredSize().width, component.getPreferredSize().height);
+            updateComponentSize();
+        }
+ setBounds( 0, 0, component.getPreferredSize().width, component.getPreferredSize().height );
     }

+    /**
+ * Since the parent ChildWrapper has no layout manager, it is the responsibility of this PSwing + * to make sure the component has its bounds set properly, otherwise it will not be drawn properly. + * This method sets the bounds of the component to be equal to its preferred size.
+     */
+    private void updateComponentSize() {
+ component.setBounds( 0, 0, component.getPreferredSize().width, component.getPreferredSize().height );
+    }
+
+    /**
+ * Determines whether the component should be resized, based on whether its actual width and height
+     * differ from its preferred width and height.
+     * @return true if the component should be resized.
+     */
     private boolean componentNeedsResizing() {
-        return component.getWidth() != component.getPreferredSize().width
- || component.getHeight() != component.getPreferredSize().height; + return component.getWidth() != component.getPreferredSize().width | | component.getHeight() != component.getPreferredSize().height;
     }

     /**
- * Determines if the Swing component should be rendered normally or as a
-     * filled rectangle.
+ * Paints the PSwing on the specified renderContext. Also determines if + * the Swing component should be rendered normally or as a filled rectangle (greeking).
      * <p/>
* The transform, clip, and composite will be set appropriately when this * object is rendered. It is up to this object to restore the transform,
@@ -365,25 +372,29 @@
      * @param renderContext Contains information about current render.
      */
     public void paint(final PPaintContext renderContext) {
+        if (componentNeedsResizing()) {
+            updateComponentSize();
+            component.validate();
+        }
         final Graphics2D g2 = renderContext.getGraphics();

-        if (defaultStroke == null) {
-            defaultStroke = new BasicStroke();
-        }
+        //Save Stroke and Font for restoring.
+        Stroke originalStroke = g2.getStroke();
+        Font originalFont = g2.getFont();

         g2.setStroke(defaultStroke);
         g2.setFont(DEFAULT_FONT);
-
-        if (component.getParent() == null) {
-            component.revalidate();
-        }
-
+
         if (shouldRenderGreek(renderContext)) {
             paintAsGreek(g2);
         }
         else {
             paint(g2);
         }
+
+        //Restore the stroke and font on the Graphics2D
+        g2.setStroke(originalStroke);
+        g2.setFont(originalFont);
     }

     /**
@@ -399,24 +410,26 @@
     }

     /**
-     * Paints the Swing component as greek.
+ * Paints the Swing component as greek. This method assumes that the stroke has been set beforehand.
      *
      * @param g2 The graphics used to render the filled rectangle
      */
     public void paintAsGreek(final Graphics2D g2) {
-        final Color background = component.getBackground();
-        final Color foreground = component.getForeground();
-        final Rectangle2D rect = getBounds();
-
-        if (background != null) {
-            g2.setColor(background);
-        }
-        g2.fill(rect);
-
-        if (foreground != null) {
-            g2.setColor(foreground);
-        }
-        g2.draw(rect);
+        //Save original color for restoring painting as greek.
+        Color originalColor = g2.getColor();
+
+        if (component.getBackground() != null) {
+            g2.setColor(component.getBackground());
+        }
+        g2.fill(getBounds());
+
+        if (component.getForeground() != null) {
+            g2.setColor(component.getForeground());
+        }
+        g2.draw(getBounds());
+
+        //Restore original color on the Graphics2D
+        g2.setColor( originalColor );
     }

     /** {@inheritDoc} */
@@ -504,20 +517,7 @@
         if (c.getFont() != null) {
             minFontSize = Math.min(minFontSize, c.getFont().getSize());
         }
-        c.addPropertyChangeListener("font", this);
-
-        // Update shape when any property (such as text or font) changes.
-        c.addPropertyChangeListener(reshapeListener);
-
-        c.addComponentListener(new ComponentAdapter() {
-            public void componentResized(final ComponentEvent e) {
-                updateBounds();
-            }
-
-            public void componentShown(final ComponentEvent e) {
-                updateBounds();
-            }
-        });
+        c.addPropertyChangeListener( "font", this );

         if (c instanceof Container) {
             initializeChildren((Container) c);
@@ -654,7 +654,7 @@
* threshold the Swing component is rendered as 'Greek' instead of painting
      * the Swing component. Defaults to {@link #DEFAULT_GREEK_THRESHOLD}.
      *
-     * @see PSwing#paintGreek(PPaintContext)
+     * @see PSwing#paintAsGreek(Graphics2D)
      * @return the current Greek threshold scale
      */
     public double getGreekThreshold() {
@@ -666,7 +666,7 @@
* scale will be below this threshold the Swing component is rendered as
      * 'Greek' instead of painting the Swing component..
      *
-     * @see PSwing#paintGreek(PPaintContext)
+     * @see PSwing#paintAsGreek(Graphics2D)
      * @param greekThreshold Greek threshold in scale
      */
     public void setGreekThreshold(final double greekThreshold) {
=======================================
--- /piccolo2d.java/trunk/extras/src/main/java/org/piccolo2d/extras/pswing/PSwingRepaintManager.java Mon May 10 20:10:56 2010 +++ /piccolo2d.java/trunk/extras/src/main/java/org/piccolo2d/extras/pswing/PSwingRepaintManager.java Mon Mar 7 11:50:37 2011
@@ -33,14 +33,13 @@

 import javax.swing.JComponent;
 import javax.swing.RepaintManager;
-import javax.swing.SwingUtilities;

 import org.piccolo2d.util.PBounds;

-
 /**
* This RepaintManager replaces the default Swing implementation, and is used to
- * intercept and repaint dirty regions of PSwing components.
+ * repaint dirty regions of PSwing components and make sure the PSwings have
+ * the appropriate size.
  * <p>
  * This is an internal class used by Piccolo to support Swing components in
* Piccolo. This should not be instantiated, though all the public methods of
@@ -50,12 +49,12 @@
  * <p>
  * PBasicRepaint Manager is an extension of RepaintManager that traps those
* repaints called by the Swing components that have been added to the PCanvas
- * and passes these repaints to the SwingVisualComponent rather than up the
+ * and passes these repaints to the PSwing rather than up the
  * component hierarchy as usually happens.
  * </p>
  * <p>
- * Also traps revalidate calls made by the Swing components added to the PCanvas
- * to reshape the applicable Visual Component.
+ * Also traps invalidate calls made by the Swing components added to the PCanvas
+ * to reshape the corresponding PSwing.
  * </p>
  * <p>
* Also keeps a list of PSwings that are painting. This disables repaint until
@@ -63,14 +62,14 @@
* by Swing's CellRendererPane which is itself a work-around. The problem is
  * that JTable's, JTree's, and JList's cell renderers need to be validated
* before repaint. Since we have to repaint the entire Swing component hierarchy - * (in the case of a Swing component group used as a Piccolo visual component).
- * This causes an infinite loop. So we introduce the restriction that no
- * repaints can be triggered by a call to paint.
+ * (in the case of a PSwing), this causes an infinite loop. So we introduce the
+ * restriction that no repaints can be triggered by a call to paint.
  * </p>
  *
  * @author Benjamin B. Bederson
  * @author Lance E. Good
  * @author Sam R. Reid
+ * @author Chris Malley (cmal...@pixelzoom.com)
  */
 public class PSwingRepaintManager extends RepaintManager {

@@ -120,19 +119,15 @@
      * @param width Width of the dirty region in the component
      * @param height Height of the dirty region in the component
      */
- public synchronized void addDirtyRegion(final JComponent component, final int x, final int y, final int width,
-            final int height) {
+ public synchronized void addDirtyRegion(final JComponent component, final int x, final int y, final int width, final int height) {
         boolean captureRepaint = false;
         JComponent childComponent = null;
-
         int captureX = x;
         int captureY = y;

-        // We have to check to see if the PCanvas
-        // (ie. the SwingWrapper) is in the components ancestry. If so,
-        // we will want to capture that repaint. However, we also will
-        // need to translate the repaint request since the component may
-        // be offset inside another component.
+ // We have to check to see if the PCanvas (ie. the SwingWrapper) is in the components ancestry. If so, we will + // want to capture that repaint. However, we also will need to translate the repaint request since the component
+        // may be offset inside another component.
for (Component comp = component; comp != null && comp.isLightweight(); comp = comp.getParent()) {
             if (comp.getParent() instanceof PSwingCanvas.ChildWrapper) {
                 captureRepaint = true;
@@ -146,34 +141,24 @@
             }
         }

-        // Now we check to see if we should capture the repaint and act
-        // accordingly
+ // Now we check to see if we should capture the repaint and act accordingly
         if (captureRepaint) {
             if (!isPainting(childComponent)) {
final double repaintW = Math.min(childComponent.getWidth() - captureX, width); final double repaintH = Math.min(childComponent.getHeight() - captureY, height);

- dispatchRepaint(childComponent, new PBounds(captureX, captureY, repaintW, repaintH));
+                //Schedule a repaint for the dirty part of the PSwing
+ getPSwing(childComponent).repaint( new PBounds( captureX, captureY, repaintW, repaintH ) );
             }
         }
         else {
             super.addDirtyRegion(component, x, y, width, height);
         }
     }
-
- private void dispatchRepaint(final JComponent childComponent, final PBounds repaintBounds) { - final PSwing pSwing = (PSwing) childComponent.getClientProperty(PSwing.PSWING_PROPERTY);
-
-        SwingUtilities.invokeLater(new Runnable() {
-            public void run() {
-                pSwing.repaint(repaintBounds);
-            }
-        });
-    }

     /**
- * This is the method "revalidate" calls in the Swing components. Overridden - * to capture revalidate calls from those Swing components being used as + * This is the method "invalidate" calls in the Swing components. Overridden + * to capture invalidation calls from those Swing components being used as
      * Piccolo visual components and to update Piccolo's visual component
* wrapper bounds (these are stored separately from the Swing component).
      * Otherwise, behaves like the superclass.
@@ -181,20 +166,21 @@
      * @param invalidComponent The Swing component that needs validation
      */
public synchronized void addInvalidComponent(final JComponent invalidComponent) {
-        final JComponent capturedComponent = invalidComponent;
-
-        if (capturedComponent.getParent() == null
- || !(capturedComponent.getParent() instanceof PSwingCanvas.ChildWrapper)) { + if (invalidComponent.getParent() == null | | !(invalidComponent.getParent() instanceof PSwingCanvas.ChildWrapper)) {
             super.addInvalidComponent(invalidComponent);
         }
         else {
-            SwingUtilities.invokeLater(new Runnable() {
-                public void run() {
-                    capturedComponent.validate();
- final PSwing pSwing = (PSwing) capturedComponent.getClientProperty(PSwing.PSWING_PROPERTY);
-                    pSwing.updateBounds();
-                }
-            });
+            invalidComponent.validate();
+            getPSwing(invalidComponent).updateBounds();
         }
     }
-}
+
+    /**
+     * Obtains the PSwing associated with the specified component.
+ * @param component the component for which to return the associated PSwing
+     * @return the associated PSwing
+     */
+    private PSwing getPSwing(JComponent component) {
+ return (PSwing) component.getClientProperty( PSwing.PSWING_PROPERTY );
+    }
+}

--
Piccolo2D Developers Group: http://groups.google.com/group/piccolo2d-dev?hl=en

Reply via email to