diff --git a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java index cefd37c..b552982 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java @@ -219,10 +219,12 @@ /*The parent listener for camera/canvas changes*/ private PropertyChangeListener parentListener = new PropertyChangeListener() { public void propertyChange( PropertyChangeEvent evt ) { - PNode source = (PNode)evt.getSource(); - PNode parent = source.getParent(); + PNode parent = (PNode) evt.getNewValue(); + clearListeners((PNode) evt.getOldValue()); if( parent != null ) { listenForCanvas( parent ); + } else { + updateCanvas( null ); } } @@ -513,7 +515,12 @@ PNode parent = p; // System.out.println( "parent = " + parent.getClass() ); - if( parent instanceof PLayer ) { + if( parent instanceof PCamera) { + PCamera cam = (PCamera) parent; + if( cam.getComponent() instanceof PSwingCanvas ) { + updateCanvas( (PSwingCanvas)cam.getComponent() ); + } + } else if( parent instanceof PLayer ) { PLayer player = (PLayer)parent; // System.out.println( "Found player: with " + player.getCameraCount() + " cameras" ); for( int i = 0; i < player.getCameraCount(); i++ ) { @@ -556,6 +563,22 @@ } /** + * Clear out all the listeners registered to make sure there are no stray references + * + * @param fromParent Parent to start with for clearing listeners + */ + private void clearListeners(PNode fromParent) { + if (fromParent == null) { + return; + } + if (listeningTo(fromParent)) { + fromParent.removePropertyChangeListener( PNode.PROPERTY_PARENT, parentListener ); + listeningTo.remove(fromParent); + clearListeners(fromParent.getParent()); + } + } + + /** * Removes this PSwing from previous PSwingCanvas (if any), and ensure that this PSwing is attached to the new PSwingCanvas. * @param newCanvas the new PSwingCanvas (may be null) */ @@ -564,8 +587,8 @@ if( canvas != null ) { canvas.removePSwing( this ); } + canvas = newCanvas; if( newCanvas != null ) { - canvas = newCanvas; canvas.addPSwing( this ); reshape(); repaint(); diff --git a/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingTest.java b/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingTest.java new file mode 100644 index 0000000..1af16d1 --- /dev/null +++ b/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingTest.java @@ -0,0 +1,37 @@ +package edu.umd.cs.piccolox.pswing; + +import junit.framework.TestCase; + +import javax.swing.*; + +import edu.umd.cs.piccolo.PNode; +import edu.umd.cs.piccolox.PFrame; + +import java.lang.ref.WeakReference; +import java.lang.ref.ReferenceQueue; + +/** + * JUnit test class to exercise PSwing bugfixes. + * + * @author Stephen Chin + */ +public class PSwingTest extends TestCase { + public void testPSwing() { + PSwing pSwing = new PSwing(new JButton("test")); + PFrame frame = new PFrame(); + frame.getCanvas().getLayer().addChild(pSwing); + frame.setVisible(true); + } + + public void testReferences() { + WeakReference pSwing = new WeakReference(new PSwing(new JButton("test")), new ReferenceQueue()); + PFrame frame = new PFrame(); + frame.getCanvas().getLayer().addChild((PNode) pSwing.get()); + frame.setVisible(true); + frame.getCanvas().getLayer().removeAllChildren(); + for (int i=0; i<20; i++) { // make sure garbage collection has happened + System.gc(); + } + assertTrue("The PSwing node should be garbage collected after removal", pSwing.isEnqueued()); + } +}