Revision: 642
Author: allain.lalonde
Date: Tue Aug  4 07:26:15 2009
Log: issue#111: merged phtml branch to trunk
http://code.google.com/p/piccolo2d/source/detail?r=642

Added:
   
/piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/nodes/PHtmlView.java
   
/piccolo2d.java/trunk/core/src/test/java/edu/umd/cs/piccolo/nodes/PHtmlViewTest.java
   
/piccolo2d.java/trunk/examples/src/main/java/edu/umd/cs/piccolo/examples/HtmlViewExample.java
Modified:
   
/piccolo2d.java/trunk/examples/src/main/java/edu/umd/cs/piccolo/examples/ExampleRunner.java

=======================================
--- /dev/null
+++  
/piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/nodes/PHtmlView.java
         
Tue Aug  4 07:26:15 2009
@@ -0,0 +1,442 @@
+/*
+ * 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 edu.umd.cs.piccolo.nodes;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+import javax.swing.JLabel;
+import javax.swing.JTextField;
+import javax.swing.plaf.basic.BasicHTML;
+import javax.swing.text.Position;
+import javax.swing.text.View;
+
+import edu.umd.cs.piccolo.PNode;
+import edu.umd.cs.piccolo.util.PPaintContext;
+
+/**
+ * PHtml is a Piccolo node for rendering HTML text. It uses a JLabel under  
the
+ * hood so you have the same restrictions regarding html as you have when  
using
+ * standard Swing components (HTML 3.2 + subset of CSS 1.0).
+ *
+ * @author Chris Malley (cmal...@pixelzoom.com)
+ * @author Sam Reid
+ * @author Allain Lalonde
+ */
+public class PHtmlView extends PNode {
+
+    private static final long serialVersionUID = 1L;
+
+    /** Default font to use if not overridden in the HTML markup. */
+    private static final Font DEFAULT_FONT = new JTextField().getFont();
+
+    /** Default font color to use if not overridden in the HTML markup */
+    private static final Color DEFAULT_HTML_COLOR = Color.BLACK;
+
+    /**
+     * The property name that identifies a change of this node's font (see
+     * {...@link #getFont getFont}). Both old and new value will be set in any
+     * property change event.
+     */
+    public static final String PROPERTY_FONT = "font";
+
+    /**
+     * The property code that identifies a change of this node's font (see
+     * {...@link #getFont getFont}). Both old and new value will be set in any
+     * property change event.
+     */
+    public static final int PROPERTY_CODE_FONT = 1 << 20;
+
+    /**
+     * The property name that identifies a change of this node's HTML (see
+     * {...@link #getHTML getHTML}). Both old and new value will be set in any
+     * property change event.
+     */
+    public static final String PROPERTY_HTML = "html";
+
+    /**
+     * The property code that identifies a change of this node's HTML (see
+     * {...@link #getHTML getHTML}). Both old and new value will be set in any
+     * property change event.
+     */
+    public static final int PROPERTY_CODE_HTML = 1 << 21;
+
+    /**
+     * The property name that identifies a change of this node's HTML  
color (see
+     * {...@link #getHtml getHTMLColor}). Both old and new value will be set  
in any
+     * property change event.
+     */
+    public static final String PROPERTY_HTML_COLOR = "html color";
+
+    /**
+     * The property code that identifies a change of this node's HTML  
color (see
+     * {...@link #getHtml getHTMLColor}). Both old and new value will be set  
in any
+     * property change event.
+     */
+    public static final int PROPERTY_CODE_HTML_COLOR = 1 << 22;
+
+    /** Underlying JLabel used to handle the rendering logic. */
+    private final JLabel htmlLabel;
+
+    /** Object that encapsulates the HTML rendering logic. */
+    private View htmlView;
+
+    /** Used to enforce bounds and wrapping on the HTML. */
+    private final Rectangle htmlBounds;
+
+    /**
+     * Creates an empty PHtml node with default font and color.
+     */
+    public PHtmlView() {
+        this(null, DEFAULT_FONT, DEFAULT_HTML_COLOR);
+    }
+
+    /**
+     * Creates a PHtml node that contains the provided HTML. It will have
+     * default font and color.
+     *
+     * @param html markup label should contain
+     */
+    public PHtmlView(final String html) {
+        this(html, DEFAULT_FONT, DEFAULT_HTML_COLOR);
+    }
+
+    /**
+     * Creates a PHtml node with the given markup and default html color.
+     *
+     * @param html markup label should contain
+     * @param htmlColor color that will be used unless overridden by the  
markup
+     */
+    public PHtmlView(final String html, final Color htmlColor) {
+        this(html, DEFAULT_FONT, htmlColor);
+    }
+
+    /**
+     * Creates a PHtml node with the given markup and default HTML color.
+     *
+     * @param html markup label should contain
+     * @param font font that will be used unless overriden by the markup
+     * @param htmlColor color that will be used unless overridden by the  
markup
+     */
+    public PHtmlView(final String html, final Font font, final Color  
htmlColor) {
+        htmlLabel = new JLabel(html);
+        htmlLabel.setFont(font);
+        htmlLabel.setForeground(htmlColor);
+        htmlBounds = new Rectangle();
+        update();
+    }
+
+    /**
+     * @return HTML being rendered by this node
+     */
+    public String getHtml() {
+        return htmlLabel.getText();
+    }
+
+    /**
+     * Changes the HTML being rendered by this node.
+     *
+     * @param newHtml markup to swap with existing HTML
+     */
+    public void setHtml(final String newHtml) {
+        if (isNewHtml(newHtml)) {
+            final String oldHtml = htmlLabel.getText();
+            htmlLabel.setText(newHtml);
+            update();
+            firePropertyChange(PROPERTY_CODE_HTML, PROPERTY_HTML, oldHtml,  
newHtml);
+        }
+    }
+
+    private boolean isNewHtml(final String html) {
+        if (html == null && getHtml() == null) {
+            return false;
+        }
+        else if (html == null || getHtml() == null) {
+            return true;
+        }
+        else {
+            return !htmlLabel.getText().equals(html);
+        }
+    }
+
+    /**
+     * Returns the default font being used when not overridden in the  
markup.
+     *
+     * @return font being used when not overridden by the markup
+     */
+    public Font getFont() {
+        return htmlLabel.getFont();
+    }
+
+    /**
+     * Set the font of this PHtml. This may be overridden by the markup  
using
+     * either styles or the font tag.
+     *
+     * @param newFont font to set as the default
+     */
+    public void setFont(final Font newFont) {
+        final Font oldFont = htmlLabel.getFont();
+        htmlLabel.setFont(newFont);
+        update();
+
+        firePropertyChange(PROPERTY_CODE_FONT, PROPERTY_FONT, oldFont,  
newFont);
+    }
+
+    /**
+     * Gets the color used to render the HTML. If you want to get the  
paint used
+     * for the node, use getPaint.
+     *
+     * @return the color used to render the HTML.
+     */
+    public Color getHtmlColor() {
+        return htmlLabel.getForeground();
+    }
+
+    /**
+     * Sets the color used to render the HTML. If you want to set the  
paint used
+     * for the node, use setPaint.
+     *
+     * @param newColor new color to use when rendering HTML
+     */
+    public void setHtmlColor(final Color newColor) {
+        final Color oldColor = htmlLabel.getForeground();
+        htmlLabel.setForeground(newColor);
+        repaint();
+        firePropertyChange(PROPERTY_CODE_HTML_COLOR, PROPERTY_HTML_COLOR,  
oldColor, newColor);
+    }
+
+    /**
+     * Applies all properties to the underlying JLabel, creates an  
htmlView and
+     * updates bounds
+     */
+    private void update() {
+        htmlLabel.setSize(htmlLabel.getPreferredSize());
+        htmlView = BasicHTML.createHTMLView(htmlLabel, htmlLabel.getText()  
== null ? "" : htmlLabel.getText());
+
+        final Rectangle2D bounds = getBounds();
+        htmlBounds.setRect(0, 0, bounds.getWidth(), bounds.getHeight());
+        repaint();
+    }
+
+    /** {...@inheritdoc} */
+    public boolean setBounds(final double x, final double y, final double  
width, final double height) {
+        final boolean boundsChanged = super.setBounds(x, y, width, height);
+        update();
+        return boundsChanged;
+    }
+
+    /** {...@inheritdoc} */
+    public boolean setBounds(final Rectangle2D newBounds) {
+        final boolean boundsChanged = super.setBounds(newBounds);
+        update();
+        return boundsChanged;
+    }
+
+    /**
+     * Paints the node. The HTML string is painted last, so it appears on  
top of
+     * any child nodes.
+     *
+     * @param paintContext the context in which painting is occurring
+     */
+    protected void paint(final PPaintContext paintContext) {
+        super.paint(paintContext);
+
+        if (htmlLabel.getWidth() != 0 && htmlLabel.getHeight() != 0) {
+            final Graphics2D g2 = paintContext.getGraphics();
+
+            htmlView.paint(g2, htmlBounds);
+        }
+    }
+
+    /**
+     * Returns the address specified in the link under the given point.
+     *
+     * @param clickedPoint
+     * @return String containing value of href for clicked link, or null  
if no
+     *         link clicked
+     */
+    public String getClickedAddress(final Point2D.Double clickedPoint) {
+        return getClickedAddress(clickedPoint.getX(), clickedPoint.getY());
+    }
+
+    /**
+     * Returns the address specified in the link under the given point.
+     *
+     * @param clickedPoint
+     * @return String containing value of href for clicked link, or null  
if no
+     *         link clicked
+     */
+    public String getClickedAddress(final double x, final double y) {
+        int position = pointToModelIndex(x, y);
+
+        final String html = htmlLabel.getText();
+
+        String address = null;
+
+        int currentPos = 0;
+        while (currentPos < html.length()) {
+            currentPos = html.indexOf('<', currentPos);
+            if (currentPos == -1 || position < currentPos) {
+                break;
+            }
+
+            final int tagStart = currentPos;
+            final int tagEnd = findTagEnd(html, currentPos);
+
+            if (tagEnd == -1) {
+                return null;
+            }
+
+            currentPos = tagEnd + 1;
+
+            final String tag = html.substring(tagStart, currentPos);
+
+            position += tag.length();
+
+            if ("</a>".equals(tag)) {
+                address = null;
+            }
+            else if (tag.startsWith("<a ")) {
+                address = extractHref(tag);
+            }
+        }
+
+        return address;
+    }
+
+    /**
+     * Returns the index into the raw text (without HTML) that the click
+     * occurred.
+     *
+     * @param x x component of the point clicked
+     * @param y y component of the point clicked
+     * @return index into the raw text (without HTML) that the click  
occurred
+     */
+    private int pointToModelIndex(final double x, final double y) {
+        final Position.Bias[] biasReturn = new Position.Bias[1];
+        return htmlView.viewToModel((float) x, (float) y, getBounds(),  
biasReturn);
+    }
+
+    /**
+     * Starting from the startPos, it finds the position at which the  
given tag
+     * ends. Returns -1 if the end of the string was encountered before  
the end
+     * of the tag was encountered.
+     *
+     * @param html raw HTML string being searched
+     * @param startPos where in the string to start searching for ">"
+     * @return index after the ">" character
+     */
+    private int findTagEnd(final String html, final int startPos) {
+        int currentPos = startPos;
+
+        currentPos++;
+
+        while (currentPos > 0 && currentPos < html.length() &&  
html.charAt(currentPos) != '>') {
+            if (html.charAt(currentPos) == '\"') {
+                currentPos = html.indexOf('\"', currentPos + 1);
+            }
+            else if (html.charAt(currentPos) == '\'') {
+                currentPos = html.indexOf('\'', currentPos + 1);
+            }
+            currentPos++;
+        }
+
+        return currentPos == 0 || currentPos >= html.length() ? -1 :  
currentPos + 1;
+    }
+
+    /**
+     * Given a tag, extracts the value of the href attribute, returns null  
if
+     * none was found.
+     *
+     * @param tag from which to extract the href value
+     * @return href value without quotes or null if not found
+     */
+    private String extractHref(final String tag) {
+        int currentPos = 0;
+
+        final String href = null;
+
+        while (currentPos >= 0 && currentPos < tag.length() - 1) {
+            currentPos = tag.indexOf('=', currentPos + 1);
+            if (currentPos != -1 && isHrefAttributeAssignment(tag,  
currentPos)) {
+                return extractHrefValue(tag, currentPos + 1);
+            }
+        }
+        return href;
+    }
+
+    /**
+     * Starting at the character after the equal sign of an href=..., it  
extract
+     * the value. Handles single, double, and no quotes.
+     *
+     * @param tag
+     * @param startPos
+     * @return value of href or null if not found.
+     */
+    private String extractHrefValue(final String tag, final int startPos) {
+        int currentPos = startPos;
+
+        if (tag.charAt(currentPos) == '\"') {
+            final int startHref = currentPos + 1;
+            currentPos = tag.indexOf('\"', startHref);
+            return currentPos == -1 ? null : tag.substring(startHref,  
currentPos);
+        }
+        else if (currentPos < tag.length() && tag.charAt(currentPos)  
== '\'') {
+            final int startHref = currentPos + 1;
+            currentPos = tag.indexOf('\'', startHref);
+            return currentPos == -1 ? null : tag.substring(startHref,  
currentPos);
+        }
+        else {
+            final int startHref = currentPos;
+
+            if (currentPos < tag.length()) {
+                do {
+                    currentPos++;
+                } while (currentPos < tag.length() &&  
tag.charAt(currentPos) != ' ' && tag.charAt(currentPos) != '>');
+            }
+            return tag.substring(startHref, currentPos);
+        }
+    }
+
+    /**
+     * Given the position in a string returns whether it points to the  
equal
+     * sign of an href attribute.
+     *
+     * @param tag html code of the tag
+     * @param equalPos the index of the assignment
+     *
+     * @return true if to left of assignment is href
+     */
+    private boolean isHrefAttributeAssignment(final String tag, final int  
equalPos) {
+        return tag.charAt(equalPos) == '=' && equalPos > 4 && "  
href".equals(tag.substring(equalPos - 5, equalPos));
+    }
+}
=======================================
--- /dev/null
+++  
/piccolo2d.java/trunk/core/src/test/java/edu/umd/cs/piccolo/nodes/PHtmlViewTest.java
     
Tue Aug  4 07:26:15 2009
@@ -0,0 +1,128 @@
+package edu.umd.cs.piccolo.nodes;
+
+import java.awt.Color;
+import java.awt.Font;
+
+import junit.framework.TestCase;
+import edu.umd.cs.piccolo.MockPropertyChangeListener;
+import edu.umd.cs.piccolo.util.PBounds;
+
+public class PHtmlViewTest extends TestCase {
+
+    private MockPropertyChangeListener mockListener;
+
+    public void setUp() {
+        mockListener = new MockPropertyChangeListener();
+    }
+
+    public void testGetClickedAddressReturnsSingleQuotedAddress() {
+        PHtmlView html = new PHtmlView("<a  
href='http://www.testing.com'>testing</a>");
+        html.setBounds(new PBounds(0, 0, 100, 100));
+        assertEquals("http://www.testing.com";,  
html.getClickedAddress(5,5));
+    }
+
+    public void testGetClickedAddressReturnsDoubleQuotedAddress() {
+        PHtmlView html = new PHtmlView("<a  
href=\"http://www.testing.com\";>testing</a>");
+        html.setBounds(new PBounds(0, 0, 100, 100));
+        assertEquals("http://www.testing.com";,  
html.getClickedAddress(5,5));
+    }
+
+    public void testBracketsAreValidInHrefs() {
+        PHtmlView html = new PHtmlView("<a href='a>b'>testing</a>");
+        html.setBounds(new PBounds(0, 0, 100, 100));
+        assertEquals("a>b", html.getClickedAddress(5,5));
+    }
+
+    public void testGetClickedAddressReturnsNullWhenInvalid() {
+        PHtmlView html = new PHtmlView("<a ='a>b'>testing</a>");
+        html.setBounds(new PBounds(0, 0, 100, 100));
+        assertNull(html.getClickedAddress(5,5));
+    }
+
+    public void testGetClickedAddressReturnsHrefWhenMissingEndAnchorTag() {
+        PHtmlView html = new PHtmlView("<a href='testing.com'>testing");
+        html.setBounds(new PBounds(0, 0, 100, 100));
+        assertEquals("testing.com", html.getClickedAddress(5,5));
+    }
+
+    public void testHandlesTricksyTitles() {
+        PHtmlView html = new PHtmlView("<a href=\"where to go\"  
title=\"this is not the href='gotcha!' \">testing</a>");
+        html.setBounds(new PBounds(0, 0, 100, 100));
+        assertEquals("where to go", html.getClickedAddress(5,5));
+    }
+
+    public void testHandlesHrefWithoutQuotes() {
+        PHtmlView html = new PHtmlView("<a href=testing.com>testing</a>");
+        html.setBounds(new PBounds(0, 0, 100, 100));
+        assertEquals("testing.com", html.getClickedAddress(5,5));
+    }
+
+    public void testUnclosedTagsCauseIgnoreOfTag() {
+        PHtmlView html = new PHtmlView("<a href='testing.com' ");
+        html.setBounds(new PBounds(0, 0, 100, 100));
+        assertNull(html.getClickedAddress(5,5));
+    }
+
+    public void testMissingEndTagCausesRemainderOfHtmlToBeLinkTarget() {
+        PHtmlView html = new PHtmlView("<a href='testing.com'>Missing End  
TAg ");
+        html.setBounds(new PBounds(0, 0, 100, 100));
+        assertEquals("testing.com", html.getClickedAddress(5,5));
+    }
+
+    public void testUnclosedQuotesCauseIgnoreOfLink() {
+        PHtmlView html = new PHtmlView("<a href='testing.com>testing");
+        html.setBounds(new PBounds(0, 0, 100, 100));
+        assertNull(html.getClickedAddress(5,5));
+    }
+
+    public void testEmptyAddressReturnsEmptyString() {
+        PHtmlView html = new PHtmlView("<a href=''>testing");
+        html.setBounds(new PBounds(0, 0, 100, 100));
+        assertEquals("", html.getClickedAddress(5,5));
+    }
+
+    public void testReturnsNullWhenClickOutsideLink() {
+        PHtmlView html = new PHtmlView("0123456789 <a href=#>testing</a>");
+        html.setBounds(new PBounds(0, 0, 100, 100));
+        assertNull(html.getClickedAddress(5,5));
+    }
+
+    public void testSetHtmlColorPersists() {
+        PHtmlView html = new PHtmlView();
+        html.setHtmlColor(Color.RED);
+        assertEquals(Color.RED, html.getHtmlColor());
+    }
+
+    public void testFontIsNotNullByDefault() {
+        PHtmlView html = new PHtmlView();
+        assertNotNull(html.getFont());
+    }
+
+    public void testHtmlColorIsNotNullByDefault() {
+        PHtmlView html = new PHtmlView();
+        assertNotNull(html.getHtmlColor());
+    }
+
+    public void testSetHtmlFiresEventOnChangeOnly() {
+        PHtmlView html = new PHtmlView();
+        html.addPropertyChangeListener(mockListener);
+        html.setHtml("testing");
+        assertEquals(1, mockListener.getPropertyChangeCount());
+        assertEquals(PHtmlView.PROPERTY_HTML,  
mockListener.getPropertyChange(0).getPropertyName());
+        html.setHtml("testing");
+        assertEquals(1, mockListener.getPropertyChangeCount());
+    }
+
+    public void testSetHtmlToNullIsAllowed() {
+        PHtmlView html = new PHtmlView();
+        html.setHtml(null);
+        assertNull(html.getHtml());
+    }
+
+    public void testSetFontPerists() {
+        PHtmlView html = new PHtmlView();
+        Font font = Font.getFont("arial");
+        html.setFont(font);
+        assertSame(font, html.getFont());
+    }
+}
=======================================
--- /dev/null
+++  
/piccolo2d.java/trunk/examples/src/main/java/edu/umd/cs/piccolo/examples/HtmlViewExample.java
    
Tue Aug  4 07:26:15 2009
@@ -0,0 +1,74 @@
+package edu.umd.cs.piccolo.examples;
+
+import java.awt.geom.Point2D;
+
+import javax.swing.JOptionPane;
+
+import edu.umd.cs.piccolo.PCanvas;
+import edu.umd.cs.piccolo.PNode;
+import edu.umd.cs.piccolo.event.PBasicInputEventHandler;
+import edu.umd.cs.piccolo.event.PInputEvent;
+import edu.umd.cs.piccolo.nodes.PHtmlView;
+import edu.umd.cs.piccolox.PFrame;
+
+public class HtmlViewExample extends PFrame {
+    private static final long serialVersionUID = 1L;
+    private StringBuffer html;
+
+    public HtmlViewExample() {
+        this(null);
+    }
+
+    public HtmlViewExample(final PCanvas aCanvas) {
+        super("HTMLExample", false, aCanvas);
+    }
+
+    public void initialize() {
+        html = new StringBuffer();
+        html.append("<p style='margin-bottom: 10px;'>");
+        html.append("This is an example <a href='#testing'>of what can</a>  
be done with PHtml.");
+        html.append("</p>");
+        html.append("<p>It supports:</p>");
+        appendFeatures();
+
+        final PHtmlView htmlNode = new PHtmlView(html.toString());
+        htmlNode.setBounds(0, 0, 400, 400);
+        getCanvas().getLayer().addChild(htmlNode);
+
+        getCanvas().addInputEventListener(new PBasicInputEventHandler() {
+            public void mouseClicked(final PInputEvent event) {
+                final PNode clickedNode = event.getPickedNode();
+                if (!(clickedNode instanceof PHtmlView)) {
+                    return;
+                }
+
+                final Point2D clickPoint =  
event.getPositionRelativeTo(clickedNode);
+                final PHtmlView htmlNode = (PHtmlView) clickedNode;
+
+                final String url = htmlNode.getClickedAddress(clickPoint);
+                JOptionPane.showMessageDialog(null, url);
+            }
+        });
+    }
+
+    private void appendFeatures() {
+        html.append("<ul>");
+        html.append("<li><b>HTML</b> 3.2</li>");
+        html.append("<li><font style='color:red; font-style:  
italic;'>Limited CSS 1.0</font></li>");
+        html.append("<li>Tables:");
+        appendTable();
+        html.append("</li>");
+        html.append("</ul>");
+    }
+
+    private void appendTable() {
+        html.append("<table border='1' cellpadding='2' cellspacing='0'>");
+        html.append("<tr><th>Col 1</th><th>Col 2</th></tr>");
+        html.append("<tr><td>Col 1 val</td><td>Col 2 val</td></tr>");
+        html.append("</table>");
+    }
+
+    public static void main(final String[] args) {
+        new HtmlViewExample();
+    }
+}
=======================================
---  
/piccolo2d.java/trunk/examples/src/main/java/edu/umd/cs/piccolo/examples/ExampleRunner.java
      
Tue Jul 28 12:46:54 2009
+++  
/piccolo2d.java/trunk/examples/src/main/java/edu/umd/cs/piccolo/examples/ExampleRunner.java
      
Tue Aug  4 07:26:15 2009
@@ -107,13 +107,13 @@
                  BirdsEyeViewExample.class, CameraExample.class,  
CenterExample.class, ChartLabelExample.class,
                  ClipExample.class, CompositeExample.class,  
DynamicExample.class, EventHandlerExample.class,
                  FullScreenNodeExample.class, GraphEditorExample.class,  
GridExample.class, GroupExample.class,
-                HandleExample.class, HelloWorldExample.class,  
HierarchyZoomExample.class, KeyEventFocusExample.class,
-                LayoutExample.class, LensExample.class,  
NavigationExample.class, NodeCacheExample.class,
-                NodeEventExample.class, NodeExample.class,  
NodeLinkExample.class, PanToExample.class,
-                PathExample.class, PositionExample.class,  
PositionPathActivityExample.class, PulseExample.class,
-                ScrollingExample.class, SelectionExample.class,  
SquiggleExample.class, StickyExample.class,
-                StickyHandleLayerExample.class, StrokeExample.class,  
TextExample.class, TooltipExample.class,
-                TwoCanvasExample.class, WaitForActivitiesExample.class });
+                HandleExample.class, HelloWorldExample.class,  
HierarchyZoomExample.class, HtmlViewExample.class,
+                KeyEventFocusExample.class, LayoutExample.class,  
LensExample.class, NavigationExample.class,
+                NodeCacheExample.class, NodeEventExample.class,  
NodeExample.class, NodeLinkExample.class,
+                PanToExample.class, PathExample.class,  
PositionExample.class, PositionPathActivityExample.class,
+                PulseExample.class, ScrollingExample.class,  
SelectionExample.class, SquiggleExample.class,
+                StickyExample.class, StickyHandleLayerExample.class,  
StrokeExample.class, TextExample.class,
+                TooltipExample.class, TwoCanvasExample.class,  
WaitForActivitiesExample.class });
      }

      private void addExampleButtons(final JPanel panel, final Class[]  
exampleClasses) {

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

Reply via email to