Revision: 595
Author: allain.lalonde
Date: Tue Jul 28 10:22:29 2009
Log: Added PHtml and HTMLExample

I've made it support link clicks by having a getClickedAddress(Point2D  
point) method.

http://code.google.com/p/piccolo2d/source/detail?r=595

Added:
   
/piccolo2d.java/branches/phtml/core/src/main/java/edu/umd/cs/piccolo/nodes/PHtml.java
   
/piccolo2d.java/branches/phtml/examples/src/main/java/edu/umd/cs/piccolo/examples/HTMLExample.java
Modified:
   
/piccolo2d.java/branches/phtml/examples/src/main/java/edu/umd/cs/piccolo/examples/ExampleRunner.java

=======================================
--- /dev/null
+++  
/piccolo2d.java/branches/phtml/core/src/main/java/edu/umd/cs/piccolo/nodes/PHtml.java
    
Tue Jul 28 10:22:29 2009
@@ -0,0 +1,242 @@
+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 java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+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
+ */
+public class PHtml extends PNode {
+
+    /**
+     * Allows for future serialization code to understand versioned binary
+     * formats.
+     */
+    private static final long serialVersionUID = 1L;
+
+    private static final Pattern tagPattern = Pattern.compile("</?[^>]+>");
+    private static final Pattern linkPattern =  
Pattern.compile("<a .*href=(\\\"([^\\\"]*)\\\"|\\\'([^\\\"]*)\\\')");
+
+    private static final Font DEFAULT_FONT = new JTextField().getFont();
+    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";
+    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";
+    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";
+    public static final int PROPERTY_CODE_HTML_COLOR = 1 << 22;
+
+    private JLabel htmlLabel;
+    private View htmlView;
+    private final Rectangle htmlBounds;
+
+    public PHtml() {
+        this(null, DEFAULT_FONT, DEFAULT_HTML_COLOR);
+    }
+
+    public PHtml(String html) {
+        this(html, DEFAULT_FONT, DEFAULT_HTML_COLOR);
+    }
+
+    public PHtml(String html, Color htmlColor) {
+        this(html, DEFAULT_FONT, htmlColor);
+    }
+
+    public PHtml(String html, Font font, 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
+     */
+    public void setHTML(String newHtml) {
+        if (isNewHtml(newHtml)) {
+            String oldHtml = htmlLabel.getText();
+            htmlLabel.setText(newHtml);
+            update();
+            firePropertyChange(PROPERTY_CODE_HTML, PROPERTY_HTML, oldHtml,  
newHtml);
+        }
+    }
+
+    private boolean isNewHtml(String html) {
+        return (htmlLabel.getText() != null && html == null) ||  
(htmlLabel.getText() == null && html != null)
+                || (!htmlLabel.getText().equals(html));
+    }
+
+    /**
+     * Gets the font.
+     *
+     * @return the font
+     */
+    public Font getFont() {
+        return htmlLabel.getFont();
+    }
+
+    /**
+     * Set the font of this PHtml.
+     */
+    public void setFont(Font newFont) {
+        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
+     */
+    public void setHTMLColor(Color newColor) {
+        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());
+
+        Rectangle2D bounds = getBounds();
+        htmlBounds.setRect(0, 0, bounds.getWidth(), bounds.getHeight());
+        repaint();
+    }
+
+    public boolean setBounds(double x, double y, double width, double  
height) {
+        boolean boundsChanged = super.setBounds(x, y, width, height);
+        update();
+        return boundsChanged;
+    }
+
+    public boolean setBounds(Rectangle2D newBounds) {
+        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
+     */
+    protected void paint(PPaintContext paintContext) {
+        super.paint(paintContext);
+
+        if (htmlLabel.getWidth() != 0 && htmlLabel.getHeight() != 0) {
+            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(Point2D clickedPoint) {
+        int position = pointToModelIndex(clickedPoint);
+
+        Matcher tagMatcher = tagPattern.matcher(htmlLabel.getText());
+
+        String address = null;
+
+        while (tagMatcher.find()) {
+            if (position <= tagMatcher.start()) {
+                break;
+            }
+            position += tagMatcher.end() - tagMatcher.start();
+
+            String tag = tagMatcher.group().toLowerCase();
+            if ("</a>".equals(tag)) {
+                address = null;
+            }
+            else {
+                Matcher linkMatcher = linkPattern.matcher(tag);
+                if (linkMatcher.find()) {
+                    address = linkMatcher.group(2);
+                    if (address == null)
+                        address = linkMatcher.group(3);
+                }
+            }
+        }
+
+        return address;
+    }
+
+    private int pointToModelIndex(Point2D clickedPoint) {
+        Position.Bias[] biasReturn = new Position.Bias[1];
+        return htmlView.viewToModel((float) clickedPoint.getX(), (float)  
clickedPoint.getY(), getBounds(), biasReturn);
+    }
+}
=======================================
--- /dev/null
+++  
/piccolo2d.java/branches/phtml/examples/src/main/java/edu/umd/cs/piccolo/examples/HTMLExample.java
       
Tue Jul 28 10:22:29 2009
@@ -0,0 +1,72 @@
+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.PHtml;
+import edu.umd.cs.piccolox.PFrame;
+
+public class HTMLExample extends PFrame {
+    private StringBuffer html;
+
+    public HTMLExample() {
+        this(null);
+    }
+
+    public HTMLExample(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 PHtml htmlNode = new PHtml(html.toString());
+        htmlNode.setBounds(0, 0, 400, 400);
+        getCanvas().getLayer().addChild(htmlNode);
+
+        getCanvas().addInputEventListener(new PBasicInputEventHandler() {
+            public void mouseClicked(PInputEvent event) {
+                PNode clickedNode = event.getPickedNode();
+                if (!(clickedNode instanceof PHtml))
+                    return;
+
+                Point2D clickPoint =  
event.getPositionRelativeTo(clickedNode);
+                PHtml htmlNode = (PHtml)clickedNode;
+
+                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(String[] args) {
+        new HTMLExample();
+    }
+}
=======================================
---  
/piccolo2d.java/branches/phtml/examples/src/main/java/edu/umd/cs/piccolo/examples/ExampleRunner.java
     
Mon Jul 27 22:02:02 2009
+++  
/piccolo2d.java/branches/phtml/examples/src/main/java/edu/umd/cs/piccolo/examples/ExampleRunner.java
     
Tue Jul 28 10:22:29 2009
@@ -86,13 +86,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, HTMLExample.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(JPanel panel, Class[] exampleClasses) {

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

Reply via email to