Revision: 635
Author: heuermh
Date: Sun Aug 2 19:49:04 2009
Log: minor API improvements to PSwing, javadoc improvements, and formatting
changes
http://code.google.com/p/piccolo2d/source/detail?r=635
Modified:
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java
=======================================
---
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java
Thu Jul 30 12:36:17 2009
+++
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java
Sun Aug 2 19:49:04 2009
@@ -36,7 +36,6 @@
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Insets;
-import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.ComponentAdapter;
@@ -51,6 +50,7 @@
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import javax.swing.Icon;
import javax.swing.JButton;
@@ -199,44 +199,49 @@
* @author Sam R. Reid
* @author Benjamin B. Bederson
* @author Lance E. Good
- *
- * 3-23-2007 edited to automatically detect PCamera/PSwingCanvas to
- * allow single-arg constructor usage
*/
public class PSwing extends PNode implements Serializable,
PropertyChangeListener {
- /**
- *
- */
+ /** Default serial version UID. */
private static final long serialVersionUID = 1L;
- /**
- * Used as a hashtable key for this object in the Swing component's
client
- * properties.
- */
+
+ /** Key for this object in the Swing component's client properties. */
public static final String PSWING_PROPERTY = "PSwing";
+
+ /** Temporary repaint bounds. */
private static PBounds TEMP_REPAINT_BOUNDS2 = new PBounds();
- /**
- * The cutoff at which the Swing component is rendered greek
- */
- private static final double GREEK_SCALE_CUT_OFF = 0.3d;
+ /** Default greek threshold, <code>0.3d</code>. */
+ private static final double DEFAULT_GREEK_THRESHOLD = 0.3d;
+
+ /** Swing component for this Swing node. */
private JComponent component = null;
+
+ /** Minimum font size. */
private double minFontSize = Double.MAX_VALUE;
+
+ /** Default stroke, <code>new BasicStroke()</code>. Cannot be made
static because BasicStroke is not serializable. */
private transient Stroke defaultStroke = new BasicStroke();
- private Font defaultFont = new Font("Serif", Font.PLAIN, 12);
+
+ /** Default font, 12 point <code>"SansSerif"</code>. Will be made
final in version 2.0. */
+ // public static final Font DEFAULT_FONT = new Font(Font.SANS_SERIF,
Font.PLAIN, 12); jdk 1.6+
+ public static final Font DEFAULT_FONT = new Font("SansSerif",
Font.PLAIN, 12);
+
+ /** Greek threshold in scale. */
+ private double greekThreshold = DEFAULT_GREEK_THRESHOLD;
+
+ /** Swing canvas for this swing node. */
private PSwingCanvas canvas;
- // //////////////////////////////////////////////////////////
- // /////Following fields are for automatic canvas/camera detection
- // //////////////////////////////////////////////////////////
/*
* Keep track of which nodes we've attached listeners to since no
built in
* support in PNode
*/
- private final ArrayList listeningTo = new ArrayList();
-
- /* The parent listener for camera/canvas changes */
+ private final List listeningTo = new ArrayList();
+
+ /* The parent listener for camera/canvas changes. */
private final PropertyChangeListener parentListener = new
PropertyChangeListener() {
+ /** {...@inheritdoc} */
public void propertyChange(final PropertyChangeEvent evt) {
final PNode parent = (PNode) evt.getNewValue();
clearListeners((PNode) evt.getOldValue());
@@ -251,9 +256,9 @@
};
/**
- * Constructs a new visual component wrapper for the Swing component.
+ * Create a new visual component wrapper for the specified Swing
component.
*
- * @param component The swing component to be wrapped
+ * @param component Swing component to be wrapped
*/
public PSwing(final JComponent component) {
this.component = component;
@@ -262,16 +267,19 @@
component.revalidate();
component.addPropertyChangeListener(new PropertyChangeListener() {
+ /** {...@inheritdoc} */
public void propertyChange(final PropertyChangeEvent evt) {
reshape();
}
});
component.addComponentListener(new ComponentAdapter() {
+ /** {...@inheritdoc} */
public void componentHidden(final ComponentEvent e) {
setVisible(false);
}
+ /** {...@inheritdoc} */
public void componentShown(final ComponentEvent e) {
setVisible(true);
}
@@ -281,17 +289,11 @@
listenForCanvas(this);
}
- /**
- * Deprecated constructor for application code still depending on this
- * signature.
- *
- * @param pSwingCanvas
- * @param component
- * @deprecated
- */
- public PSwing(final PSwingCanvas pSwingCanvas, final JComponent
component) {
+ /** @deprecated by {...@link PSwing(JComponent)} */
+ public PSwing(final PSwingCanvas swingCanvas, final JComponent
component) {
this(component);
}
+
/**
* Ensures the bounds of the underlying component are accurate, and
sets the
@@ -312,57 +314,48 @@
setBounds(0, 0, width, height);
}
- /**
- * Determines if the Swing component should be rendered normally or as
a
- * filled rectangle.
- * <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,
- * clip, and composite of the Graphics2D if this node changes any of
them.
- * However, the color, font, and stroke are unspecified by Piccolo.
This
- * object should set those things if they are used, but they do not
need to
- * be restored.
- *
- * @param renderContext Contains information about current render.
- */
- public void paint(final PPaintContext renderContext) {
- final Graphics2D g2 = renderContext.getGraphics();
+ /** {...@inheritdoc} */
+ protected void paint(final PPaintContext paintContext) {
+ final Graphics2D graphics = paintContext.getGraphics();
if (defaultStroke == null) {
defaultStroke = new BasicStroke();
}
- g2.setStroke(defaultStroke);
-
- if (defaultFont == null) {
- defaultFont = new Font("Serif", Font.PLAIN, 12);
- }
-
- g2.setFont(defaultFont);
+ graphics.setStroke(defaultStroke);
+
+ graphics.setFont(DEFAULT_FONT);
if (component.getParent() == null) {
- // pSwingCanvas.getSwingWrapper().add( component );
component.revalidate();
}
if (component instanceof JLabel) {
final JLabel label = (JLabel) component;
- enforceNoEllipsis(label.getText(), label.getIcon(),
label.getIconTextGap(), g2);
+ enforceNoEllipsis(label.getText(), label.getIcon(),
label.getIconTextGap(), graphics);
}
else if (component instanceof JButton) {
final JButton button = (JButton) component;
- enforceNoEllipsis(button.getText(), button.getIcon(),
button.getIconTextGap(), g2);
+ enforceNoEllipsis(button.getText(), button.getIcon(),
button.getIconTextGap(), graphics);
}
- if (shouldRenderGreek(renderContext)) {
- paintAsGreek(g2);
+ if (shouldRenderGreek(paintContext)) {
+ paintGreek(paintContext);
}
else {
- paint(g2);
+ paintComponent(paintContext);
}
}
- private void enforceNoEllipsis(final String text, final Icon icon,
final int iconGap, final Graphics2D g2) {
- final Rectangle2D textBounds =
component.getFontMetrics(component.getFont()).getStringBounds(text, g2);
+ /**
+ * Workaround to prevent text-rendering Swing components from drawing
an ellipsis incorrectly.
+ *
+ * @param text text
+ * @param icon icon
+ * @param iconGap icon gap
+ * @param graphics graphics
+ */
+ private void enforceNoEllipsis(final String text, final Icon icon,
final int iconGap, final Graphics2D graphics) {
+ final Rectangle2D textBounds =
component.getFontMetrics(component.getFont()).getStringBounds(text,
graphics);
double minAcceptableWidth = textBounds.getWidth();
double minAcceptableHeight = textBounds.getHeight();
@@ -380,31 +373,67 @@
}
}
- protected boolean shouldRenderGreek(final PPaintContext renderContext)
{
- return renderContext.getScale() < GREEK_SCALE_CUT_OFF
- // && pSwingCanvas.getInteracting()
- || minFontSize * renderContext.getScale() < 0.5;
+ /**
+ * Return the greek threshold in scale. When the scale will be below
this
+ * threshold the Swing component is rendered as 'greek' instead of
painting
+ * the Swing component. Defaults to {...@link DEFAULT_GREEK_THRESHOLD}.
+ *
+ * @see PSwing#paintGreek(PPaintContext)
+ * @return the current greek threshold in scale
+ */
+ public double getGreekThreshold() {
+ return greekThreshold;
}
/**
- * Paints the Swing component as greek.
+ * Set the greek threshold in scale to <code>greekThreshold</code>.
When the
+ * scale will be below this threshold the Swing component is rendered
as
+ * 'greek' instead of painting the Swing component..
*
- * @param g2 The graphics used to render the filled rectangle
+ * @see PSwing#paintGreek(PPaintContext)
+ * @param greekThreshold greek threshold in scale
*/
- public void paintAsGreek(final Graphics2D g2) {
+ public void setGreekThreshold(final double greekThreshold) {
+ this.greekThreshold = greekThreshold;
+ invalidatePaint();
+ }
+
+ /**
+ * Return true if this Swing node should render as greek given the
specified
+ * paint context.
+ *
+ * @param paintContext paint context
+ * @return true if this Swing node should render as greek given the
+ * specified paint context
+ */
+ protected boolean shouldRenderGreek(final PPaintContext paintContext) {
+ return paintContext.getScale() < greekThreshold
+ || minFontSize * paintContext.getScale() < 0.5;
+ }
+
+ /**
+ * Paint the Swing component as greek with the specified paint
context. The
+ * implementation in this class paints a rectangle with the Swing
+ * component's background color and paints a stroke with the Swing
+ * component's foreground color.
+ *
+ * @param paintContext paint context
+ */
+ protected void paintGreek(PPaintContext paintContext) {
+ final Graphics2D graphics = paintContext.getGraphics();
final Color background = component.getBackground();
final Color foreground = component.getForeground();
final Rectangle2D rect = getBounds();
if (background != null) {
- g2.setColor(background);
- }
- g2.fill(rect);
+ graphics.setColor(background);
+ }
+ graphics.fill(rect);
if (foreground != null) {
- g2.setColor(foreground);
- }
- g2.draw(rect);
+ graphics.setColor(foreground);
+ }
+ graphics.draw(rect);
}
/**
@@ -418,39 +447,31 @@
}
/**
- * Renders to a buffered image, then draws that image to the drawing
surface
- * associated with g2 (usually the screen).
- *
- * @param g2 graphics context for rendering the JComponent
+ * Paint the Swing component with the specified paint context.
+ *
+ * @param paintContext paint context
*/
- public void paint(final Graphics2D g2) {
+ protected void paintComponent(final PPaintContext paintContext) {
if (component.getBounds().isEmpty()) {
// The component has not been initialized yet.
return;
}
+ final Graphics2D graphics = paintContext.getGraphics();
final PSwingRepaintManager manager = (PSwingRepaintManager)
RepaintManager.currentManager(component);
manager.lockRepaint(component);
-
- final RenderingHints oldHints = g2.getRenderingHints();
-
- g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
- g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
-
- component.paint(g2);
-
- g2.setRenderingHints(oldHints);
-
+ component.paint(graphics);
manager.unlockRepaint(component);
}
+ /** {...@inheritdoc} */
public void setVisible(final boolean visible) {
super.setVisible(visible);
component.setVisible(visible);
}
/**
- * Repaints the specified portion of this visual component Note that
the
+ * Repaints the specified portion of this visual component. Note that
the
* input parameter may be modified as a result of this call.
*
* @param repaintBounds
@@ -471,9 +492,9 @@
}
/**
- * Returns the Swing component that this visual component wraps
+ * Return the Swing component that this Swing node wraps.
*
- * @return The Swing component that this visual component wraps
+ * @return the Swing component that this Swing node wraps
*/
public JComponent getComponent() {
return component;
@@ -525,23 +546,19 @@
}
}
- /**
- * Listens for changes in font on components rooted at this PSwing
- */
+ /** {...@inheritdoc} */
public void propertyChange(final PropertyChangeEvent evt) {
if (component.isAncestorOf((Component) evt.getSource()) &&
((Component) evt.getSource()).getFont() != null) {
minFontSize = Math.min(minFontSize, ((Component)
evt.getSource()).getFont().getSize());
}
}
+ /** {...@inheritdoc} */
private void readObject(final ObjectInputStream in) throws
IOException, ClassNotFoundException {
in.defaultReadObject();
init(component);
}
- // //////////////////////////////////////////////////////////
- // /////Start methods for automatic canvas detection
- // //////////////////////////////////////////////////////////
/**
* Attaches a listener to the specified node and all its parents to
listen
* for a change in the PSwingCanvas. Only PROPERTY_PARENT listeners are
@@ -558,7 +575,6 @@
listenToNode(p);
final PNode parent = p;
- // System.out.println( "parent = " + parent.getClass() );
if (parent instanceof PCamera) {
final PCamera cam = (PCamera) parent;
if (cam.getComponent() instanceof PSwingCanvas) {
@@ -567,8 +583,6 @@
}
else if (parent instanceof PLayer) {
final PLayer player = (PLayer) parent;
- // System.out.println( "Found player: with " +
- // player.getCameraCount() + " cameras" );
for (int i = 0; i < player.getCameraCount(); i++) {
final PCamera cam = player.getCamera(i);
if (cam.getComponent() instanceof PSwingCanvas) {
@@ -588,7 +602,6 @@
* @param node the node to listen to for parent/pcamera/pcanvas changes
*/
private void listenToNode(final PNode node) {
- // System.out.println( "listeningTo.size() = " +
listeningTo.size() );
if (!listeningTo(node)) {
listeningTo.add(node);
node.addPropertyChangeListener(PNode.PROPERTY_PARENT,
parentListener);
@@ -649,7 +662,4 @@
}
}
}
- // //////////////////////////////////////////////////////////
- // /////End methods for automatic canvas detection
- // //////////////////////////////////////////////////////////
-}
+}
--~--~---------~--~----~------------~-------~--~----~
Piccolo2D Developers Group: http://groups.google.com/group/piccolo2d-dev?hl=en
-~----------~----~----~----~------~----~------~--~---