This adds support for linking in CSS stylesheets via the <link> tag,
adds basic support for paring the shorthand 'background' attribute and
fixes a couple of minor bugs and stability improvements.
2006-11-11 Roman Kennke <[EMAIL PROTECTED]>
* gnu/javax/swing/text/html/css/CSSColor.java
(isValidColor): New helper method. Checks strings if they
form a valid color value.
* gnu/javax/swing/text/html/css/Length.java
(Length): Catch number format exceptions.
* javax/swing/text/html/CSS.java
(addInternal): New method. Checks for shorthand CSS attributes
and parses them.
(parseBackgroundShorthand): New method. Parses the background
shorthand attribute.
* javax/swing/text/html/HTMLDocument.java
(HTMLReader.LinkAction): Made class a subclass of HiddenAction.
(HTMLReader.LinkAction.start): Implemented to load the linked
stylesheet.
(HTMLReader.LinkAction.end): Removed. This is not needed.
* javax/swing/text/html/StyleSheet.java
(CSSStyleSheetParserCallback.declaration): Push declaration
through CSS.addInternal() to parse shorthand attributes.
(addCSSAttribute): Push declaration through CSS.addInternal()
to parse shorthand attributes.
(importStyleSheet): Implemented. This adds a stylesheet from
an URL.
* javax/swing/text/html/TableView.java
(calculateColumnRequirements): Increase column index for
non CellView children to avoid endless loop.
* javax/swing/text/CompositeView.java
(setParent): Comparen with numChildren not with real arraylength.
/Roman
Index: javax/swing/text/CompositeView.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/CompositeView.java,v
retrieving revision 1.22
diff -u -1 -5 -r1.22 CompositeView.java
--- javax/swing/text/CompositeView.java 28 Aug 2006 15:52:05 -0000 1.22
+++ javax/swing/text/CompositeView.java 11 Nov 2006 11:01:12 -0000
@@ -122,31 +122,31 @@
// Harmony's tests this is not what the RI does.
replace(0, 0, newChildren);
}
}
/**
* Sets the parent of this <code>View</code>.
* In addition to setting the parent, this calls [EMAIL PROTECTED] #loadChildren}, if
* this <code>View</code> does not already have its children initialized.
*
* @param parent the parent to set
*/
public void setParent(View parent)
{
super.setParent(parent);
- if (parent != null && ((children == null) || children.length == 0))
+ if (parent != null && numChildren == 0)
loadChildren(getViewFactory());
}
/**
* Returns the number of child views.
*
* @return the number of child views
*/
public int getViewCount()
{
return numChildren;
}
/**
* Returns the child view at index <code>n</code>.
Index: javax/swing/text/html/CSS.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/CSS.java,v
retrieving revision 1.8
diff -u -1 -5 -r1.8 CSS.java
--- javax/swing/text/html/CSS.java 7 Nov 2006 12:57:13 -0000 1.8
+++ javax/swing/text/html/CSS.java 11 Nov 2006 11:01:12 -0000
@@ -34,30 +34,33 @@
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package javax.swing.text.html;
import gnu.javax.swing.text.html.css.BorderWidth;
import gnu.javax.swing.text.html.css.CSSColor;
import gnu.javax.swing.text.html.css.FontSize;
import gnu.javax.swing.text.html.css.FontStyle;
import gnu.javax.swing.text.html.css.FontWeight;
import gnu.javax.swing.text.html.css.Length;
import java.io.Serializable;
import java.util.HashMap;
+import java.util.StringTokenizer;
+
+import javax.swing.text.MutableAttributeSet;
/**
* Provides CSS attributes to be used by the HTML view classes. The constants
* defined here are used as keys for text attributes for use in
* [EMAIL PROTECTED] javax.swing.text.AttributeSet}s of [EMAIL PROTECTED] javax.swing.text.Element}s.
*
* @author Roman Kennke ([EMAIL PROTECTED])
*/
public class CSS implements Serializable
{
/**
* Returns an array of all CSS attributes.
*
* @return All available CSS.Attribute objects.
*/
@@ -512,16 +515,35 @@
o = new CSSColor(v);
else if (att == Attribute.MARGIN || att == Attribute.MARGIN_BOTTOM
|| att == Attribute.MARGIN_LEFT || att == Attribute.MARGIN_RIGHT
|| att == Attribute.MARGIN_TOP || att == Attribute.WIDTH
|| att == Attribute.HEIGHT)
o = new Length(v);
else if (att == Attribute.BORDER_WIDTH || att == Attribute.BORDER_TOP_WIDTH
|| att == Attribute.BORDER_LEFT_WIDTH
|| att == Attribute.BORDER_RIGHT_WIDTH
|| att == Attribute.BORDER_BOTTOM_WIDTH)
o = new BorderWidth(v);
else
o = v;
return o;
}
+
+ static void addInternal(MutableAttributeSet atts, Attribute a, String v)
+ {
+ if (a == Attribute.BACKGROUND)
+ parseBackgroundShorthand(atts, v);
+ }
+
+ private static void parseBackgroundShorthand(MutableAttributeSet atts,
+ String v)
+ {
+ StringTokenizer tokens = new StringTokenizer(v, " ");
+ while (tokens.hasMoreElements())
+ {
+ String token = tokens.nextToken();
+ if (CSSColor.isValidColor(token))
+ atts.addAttribute(Attribute.BACKGROUND_COLOR,
+ getValue(Attribute.BACKGROUND_COLOR, token));
+ }
+ }
}
Index: javax/swing/text/html/HTMLDocument.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/HTMLDocument.java,v
retrieving revision 1.48
diff -u -1 -5 -r1.48 HTMLDocument.java
--- javax/swing/text/html/HTMLDocument.java 8 Nov 2006 11:21:57 -0000 1.48
+++ javax/swing/text/html/HTMLDocument.java 11 Nov 2006 11:01:13 -0000
@@ -30,30 +30,31 @@
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package javax.swing.text.html;
import gnu.classpath.NotImplementedException;
import java.io.IOException;
import java.io.StringReader;
+import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Stack;
import java.util.Vector;
import javax.swing.DefaultButtonModel;
import javax.swing.JEditorPane;
import javax.swing.JToggleButton;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Document;
import javax.swing.text.Element;
@@ -980,51 +981,95 @@
// We read in all the stylesheets that are embedded or referenced
// inside the header.
if (styles != null)
{
int numStyles = styles.size();
for (int i = 0; i < numStyles; i++)
{
String style = (String) styles.get(i);
getStyleSheet().addRule(style);
}
}
super.end(t);
}
}
- class LinkAction extends TagAction
+ class LinkAction extends HiddenAction
{
/**
* This method is called when a start tag is seen for one of the types
* of tags associated with this Action.
*/
public void start(HTML.Tag t, MutableAttributeSet a)
- throws NotImplementedException
{
- // FIXME: Implement.
+ super.start(t, a);
+ String type = (String) a.getAttribute(HTML.Attribute.TYPE);
+ if (type == null)
+ type = "text/css";
+ if (type.equals("text/css"))
+ {
+ String rel = (String) a.getAttribute(HTML.Attribute.REL);
+ String media = (String) a.getAttribute(HTML.Attribute.MEDIA);
+ String title = (String) a.getAttribute(HTML.Attribute.TITLE);
+ if (media == null)
+ media = "all";
+ else
+ media = media.toLowerCase();
+ if (rel != null)
+ {
+ rel = rel.toLowerCase();
+ if ((media.indexOf("all") != -1
+ || media.indexOf("screen") != -1)
+ && (rel.equals("stylesheet")))
+ {
+ String href = (String) a.getAttribute(HTML.Attribute.HREF);
+ URL url = null;
+ try
+ {
+ url = new URL(baseURL, href);
+ }
+ catch (MalformedURLException ex)
+ {
+ try
+ {
+ url = new URL(href);
+ }
+ catch (MalformedURLException ex2)
+ {
+ url = null;
+ }
+ }
+ if (url != null)
+ {
+ try
+ {
+ getStyleSheet().importStyleSheet(url);
+ }
+ catch (Exception ex)
+ {
+ // Don't let exceptions and runtime exceptions
+ // in CSS parsing disprupt the HTML parsing
+ // process. But inform the user/developer
+ // on the console about it.
+ ex.printStackTrace();
+ }
+ }
+ }
+ }
+ }
}
- /**
- * Called when an end tag is seen for one of the types of tags associated
- * with this Action.
- */
- public void end(HTML.Tag t)
- throws NotImplementedException
- {
- // FIXME: Implement.
- }
}
class MapAction extends TagAction
{
/**
* This method is called when a start tag is seen for one of the types
* of tags associated with this Action.
*/
public void start(HTML.Tag t, MutableAttributeSet a)
throws NotImplementedException
{
// FIXME: Implement.
}
/**
Index: javax/swing/text/html/StyleSheet.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/StyleSheet.java,v
retrieving revision 1.13
diff -u -1 -5 -r1.13 StyleSheet.java
--- javax/swing/text/html/StyleSheet.java 10 Nov 2006 08:57:26 -0000 1.13
+++ javax/swing/text/html/StyleSheet.java 11 Nov 2006 11:01:14 -0000
@@ -38,31 +38,34 @@
package javax.swing.text.html;
import gnu.javax.swing.text.html.css.CSSColor;
import gnu.javax.swing.text.html.css.CSSParser;
import gnu.javax.swing.text.html.css.CSSParserCallback;
import gnu.javax.swing.text.html.css.FontSize;
import gnu.javax.swing.text.html.css.FontStyle;
import gnu.javax.swing.text.html.css.FontWeight;
import gnu.javax.swing.text.html.css.Length;
import gnu.javax.swing.text.html.css.Selector;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
+import java.io.BufferedReader;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.Reader;
import java.io.Serializable;
import java.io.StringReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import javax.swing.border.Border;
import javax.swing.event.ChangeListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.Element;
@@ -142,30 +145,31 @@
{
css.add(style);
style = null;
}
/**
* Called when a declaration is parsed.
*
* @param property the property
* @param value the value
*/
public void declaration(String property, String value)
{
CSS.Attribute cssAtt = CSS.getAttribute(property);
Object val = CSS.getValue(cssAtt, value);
+ CSS.addInternal(style, cssAtt, value);
if (cssAtt != null)
style.addAttribute(cssAtt, val);
}
}
/**
* Represents a style that is defined by a CSS rule.
*/
private class CSSStyle
extends SimpleAttributeSet
implements Style, Comparable
{
static final int PREC_UA = 400000;
@@ -584,37 +588,50 @@
}
}
/**
* Returns an array of the linked StyleSheets. May return null.
*
* @return - An array of the linked StyleSheets.
*/
public StyleSheet[] getStyleSheets()
{
return styleSheet;
}
/**
* Imports a style sheet from the url. The rules are directly added to the
- * receiver.
+ * receiver. This is usually called when a <link> tag is resolved in an
+ * HTML document.
*
- * @param url - the URL to import the StyleSheet from.
+ * @param url the URL to import the StyleSheet from
*/
public void importStyleSheet(URL url)
{
- // FIXME: Not implemented
+ try
+ {
+ InputStream in = url.openStream();
+ Reader r = new BufferedReader(new InputStreamReader(in));
+ CSSStyleSheetParserCallback cb =
+ new CSSStyleSheetParserCallback(CSSStyle.PREC_AUTHOR_NORMAL);
+ CSSParser parser = new CSSParser(r, cb);
+ parser.parse();
+ }
+ catch (IOException ex)
+ {
+ // We can't do anything about it I guess.
+ }
}
/**
* Sets the base url. All import statements that are relative, will be
* relative to base.
*
* @param base -
* the base URL.
*/
public void setBase(URL base)
{
this.base = base;
}
/**
@@ -626,30 +643,31 @@
{
return base;
}
/**
* Adds a CSS attribute to the given set.
*
* @param attr - the attribute set
* @param key - the attribute to add
* @param value - the value of the key
*/
public void addCSSAttribute(MutableAttributeSet attr, CSS.Attribute key,
String value)
{
Object val = CSS.getValue(key, value);
+ CSS.addInternal(attr, key, value);
attr.addAttribute(key, val);
}
/**
* Adds a CSS attribute to the given set.
* This method parses the value argument from HTML based on key.
* Returns true if it finds a valid value for the given key,
* and false otherwise.
*
* @param attr - the attribute set
* @param key - the attribute to add
* @param value - the value of the key
* @return true if a valid value was found.
*/
public boolean addCSSAttributeFromHTML(MutableAttributeSet attr, CSS.Attribute key,
Index: javax/swing/text/html/TableView.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/TableView.java,v
retrieving revision 1.4
diff -u -1 -5 -r1.4 TableView.java
--- javax/swing/text/html/TableView.java 10 Nov 2006 14:47:21 -0000 1.4
+++ javax/swing/text/html/TableView.java 11 Nov 2006 11:01:14 -0000
@@ -455,30 +455,32 @@
(int) (req.minimum
/ columnWidths[c].getValue()));
relTotal.preferred =
Math.max(relTotal.preferred,
(int) (req.preferred
/ columnWidths[c].getValue()));
relTotal.maximum =
Math.max(relTotal.maximum,
(int) (req.maximum
/ columnWidths[c].getValue()));
totalPercent += columnWidths[c].getValue();
}
}
c += colSpan;
}
+ else
+ c++;
}
// Update the total requirements as follows:
// 1. Multiply the absolute requirements with 1 - totalPercent. This
// gives the total requirements based on the wishes of the absolute
// cells.
// 2. Take the maximum of this value and the total relative
// requirements. Now we should have enough space for whatever cell
// in this column.
// 3. Take the maximum of this value and the previous maximum value.
total.minimum *= 1.F / (1.F - totalPercent);
total.preferred *= 1.F / (1.F - totalPercent);
total.maximum *= 1.F / (1.F - totalPercent);
int rowTotalMin = Math.max(total.minimum, relTotal.minimum);
Index: gnu/javax/swing/text/html/css/CSSColor.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/javax/swing/text/html/css/CSSColor.java,v
retrieving revision 1.1
diff -u -1 -5 -r1.1 CSSColor.java
--- gnu/javax/swing/text/html/css/CSSColor.java 25 Aug 2006 11:40:44 -0000 1.1
+++ gnu/javax/swing/text/html/css/CSSColor.java 11 Nov 2006 11:01:14 -0000
@@ -28,30 +28,32 @@
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.javax.swing.text.html.css;
import java.awt.Color;
import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Set;
/**
* Converts CSS color values into AWT Color values.
*
* @author Roman Kennke ([EMAIL PROTECTED])
*/
public class CSSColor
{
private static final HashMap COLOR_MAP;
static
{
COLOR_MAP = new HashMap();
COLOR_MAP.put("maroon", "#800000");
COLOR_MAP.put("red", "#ff0000");
@@ -119,16 +121,43 @@
/**
* Returns the converted color.
*
* @return the converted color
*/
public Color getValue()
{
return color;
}
public String toString()
{
return value;
}
+
+ /**
+ * Returns <code>true</code> if the specified value is a valid color value,
+ * <code>false</code> otherwise.
+ *
+ * @param val the value to check
+ *
+ * @return <code>true</code> if the specified value is a valid color value,
+ * <code>false</code> otherwise
+ */
+ public static boolean isValidColor(String val)
+ {
+ boolean ret = false;
+ if (val.charAt(0) == '#')
+ ret = true;
+ else
+ {
+ Set colors = COLOR_MAP.keySet();
+ for (Iterator i = colors.iterator(); i.hasNext() && ret == false;)
+ {
+ String color = (String) i.next();
+ if (color.equalsIgnoreCase(val))
+ ret = true;
+ }
+ }
+ return ret;
+ }
}
Index: gnu/javax/swing/text/html/css/Length.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/javax/swing/text/html/css/Length.java,v
retrieving revision 1.4
diff -u -1 -5 -r1.4 Length.java
--- gnu/javax/swing/text/html/css/Length.java 9 Nov 2006 16:31:30 -0000 1.4
+++ gnu/javax/swing/text/html/css/Length.java 11 Nov 2006 11:01:14 -0000
@@ -59,64 +59,72 @@
/**
* Indicates when the value is a percentage value.
*/
private boolean isPercentage;
/**
* Creates a new length converter instance.
*
* @param val the CSS value
*/
public Length(String val)
{
value = val;
int i = value.indexOf("px");
int percent = value.indexOf("%");
- floatValue = 0.0F;
- if (i != -1)
+ try
{
- String sub = value.substring(0, i);
- floatValue = Float.parseFloat(sub);
+ floatValue = 0.0F;
+ if (i != -1)
+ {
+ String sub = value.substring(0, i);
+ floatValue = Float.parseFloat(sub);
+ }
+ else if (percent != -1)
+ {
+ isPercentage = true;
+ String sub = value.substring(0, percent);
+ floatValue = Float.parseFloat(sub) / 100;
+ }
+ else
+ {
+ // TODO: Implement other length options.
+ floatValue = Float.parseFloat(value);
+ }
}
- else if (percent != -1)
+ catch (NumberFormatException ex)
{
- isPercentage = true;
- String sub = value.substring(0, percent);
- floatValue = Float.parseFloat(sub) / 100;
- }
- else
- {
- // TODO: Implement other length options.
- floatValue = Float.parseFloat(value);
+ // Don't let such small problems interrupt CSS parsing.
+ System.err.println("couldn't parse: " + val);
}
}
/**
* Returns the value converted to pixels.
*
* @return the value converted to pixels
*/
public float getValue()
{
return floatValue;
}
/**
* Returns the absolute span for the case when this length value is
* a relative value.
*
- * @param span the target span
+ * @param available the target span
*
* @return the absolute span
*/
public float getValue(float available)
{
float span = floatValue;
if (isPercentage)
span *= available;
return span;
}
/**
* Returns <code>true</code> when the length value is a percentage
* value, <code>false</code> otherwise.
*