summaryrefslogtreecommitdiff
path: root/libjava/classpath/javax/swing/text/html
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/javax/swing/text/html')
-rw-r--r--libjava/classpath/javax/swing/text/html/BRView.java70
-rw-r--r--libjava/classpath/javax/swing/text/html/BlockView.java721
-rw-r--r--libjava/classpath/javax/swing/text/html/CSS.java736
-rw-r--r--libjava/classpath/javax/swing/text/html/CSSBorder.java421
-rw-r--r--libjava/classpath/javax/swing/text/html/CSSParser.java561
-rw-r--r--libjava/classpath/javax/swing/text/html/FormSubmitEvent.java123
-rw-r--r--libjava/classpath/javax/swing/text/html/FormView.java870
-rw-r--r--libjava/classpath/javax/swing/text/html/FrameSetView.java274
-rw-r--r--libjava/classpath/javax/swing/text/html/FrameView.java233
-rw-r--r--libjava/classpath/javax/swing/text/html/HRuleView.java189
-rw-r--r--libjava/classpath/javax/swing/text/html/HTML.java1253
-rw-r--r--libjava/classpath/javax/swing/text/html/HTMLDocument.java2298
-rw-r--r--libjava/classpath/javax/swing/text/html/HTMLEditorKit.java1520
-rw-r--r--libjava/classpath/javax/swing/text/html/HTMLFrameHyperlinkEvent.java130
-rw-r--r--libjava/classpath/javax/swing/text/html/HTMLWriter.java1088
-rw-r--r--libjava/classpath/javax/swing/text/html/ImageView.java591
-rw-r--r--libjava/classpath/javax/swing/text/html/InlineView.java307
-rw-r--r--libjava/classpath/javax/swing/text/html/ListView.java128
-rw-r--r--libjava/classpath/javax/swing/text/html/MinimalHTMLWriter.java453
-rw-r--r--libjava/classpath/javax/swing/text/html/MultiAttributeSet.java213
-rw-r--r--libjava/classpath/javax/swing/text/html/MultiStyle.java136
-rw-r--r--libjava/classpath/javax/swing/text/html/NullView.java102
-rw-r--r--libjava/classpath/javax/swing/text/html/ObjectView.java110
-rw-r--r--libjava/classpath/javax/swing/text/html/Option.java159
-rw-r--r--libjava/classpath/javax/swing/text/html/ParagraphView.java322
-rw-r--r--libjava/classpath/javax/swing/text/html/ResetableModel.java50
-rw-r--r--libjava/classpath/javax/swing/text/html/ResetablePlainDocument.java82
-rw-r--r--libjava/classpath/javax/swing/text/html/ResetableToggleButtonModel.java70
-rw-r--r--libjava/classpath/javax/swing/text/html/SelectComboBoxModel.java84
-rw-r--r--libjava/classpath/javax/swing/text/html/SelectListModel.java106
-rw-r--r--libjava/classpath/javax/swing/text/html/StyleSheet.java1455
-rw-r--r--libjava/classpath/javax/swing/text/html/TableView.java974
-rw-r--r--libjava/classpath/javax/swing/text/html/ViewAttributeSet.java163
-rw-r--r--libjava/classpath/javax/swing/text/html/package.html50
-rw-r--r--libjava/classpath/javax/swing/text/html/parser/AttributeList.java294
-rw-r--r--libjava/classpath/javax/swing/text/html/parser/ContentModel.java223
-rw-r--r--libjava/classpath/javax/swing/text/html/parser/DTD.java609
-rw-r--r--libjava/classpath/javax/swing/text/html/parser/DTDConstants.java292
-rw-r--r--libjava/classpath/javax/swing/text/html/parser/DocumentParser.java268
-rw-r--r--libjava/classpath/javax/swing/text/html/parser/Element.java317
-rw-r--r--libjava/classpath/javax/swing/text/html/parser/Entity.java183
-rw-r--r--libjava/classpath/javax/swing/text/html/parser/Parser.java446
-rw-r--r--libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java207
-rw-r--r--libjava/classpath/javax/swing/text/html/parser/TagElement.java142
-rw-r--r--libjava/classpath/javax/swing/text/html/parser/package.html50
45 files changed, 19073 insertions, 0 deletions
diff --git a/libjava/classpath/javax/swing/text/html/BRView.java b/libjava/classpath/javax/swing/text/html/BRView.java
new file mode 100644
index 000000000..6f465c9d1
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/BRView.java
@@ -0,0 +1,70 @@
+/* BRView.java -- HTML BR tag view
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import javax.swing.text.Element;
+
+/**
+ * Handled the HTML BR tag.
+ */
+class BRView
+ extends InlineView
+{
+ /**
+ * Creates the new BR view.
+ *
+ * @param elem the HTML element, representing the view.
+ */
+ public BRView(Element elem)
+ {
+ super(elem);
+ }
+
+ /**
+ * Always return ForcedBreakWeight for the X_AXIS, BadBreakWeight for the
+ * Y_AXIS.
+ */
+ public int getBreakWeight(int axis, float pos, float len)
+ {
+ if (axis == X_AXIS)
+ return ForcedBreakWeight;
+ else
+ return super.getBreakWeight(axis, pos, len);
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/BlockView.java b/libjava/classpath/javax/swing/text/html/BlockView.java
new file mode 100644
index 000000000..1c3397126
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/BlockView.java
@@ -0,0 +1,721 @@
+/* BlockView.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import gnu.javax.swing.text.html.css.Length;
+
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.util.HashMap;
+
+import javax.swing.SizeRequirements;
+import javax.swing.event.DocumentEvent;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BoxView;
+import javax.swing.text.Element;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+
+/**
+ * @author Lillian Angel <langel@redhat.com>
+ */
+public class BlockView extends BoxView
+{
+
+ /**
+ * Stores information about child positioning according to the
+ * CSS attributes position, left, right, top and bottom.
+ */
+ private static class PositionInfo
+ {
+ // TODO: Use enums when available.
+
+ /**
+ * Static positioning. This is the default and is thus rarely really
+ * used.
+ */
+ static final int STATIC = 0;
+
+ /**
+ * Relative positioning. The box is teaked relative to its static
+ * computed bounds.
+ */
+ static final int RELATIVE = 1;
+
+ /**
+ * Absolute positioning. The box is moved relative to the parent's box.
+ */
+ static final int ABSOLUTE = 2;
+
+ /**
+ * Like ABSOLUTE, with some fixation against the viewport (not yet
+ * implemented).
+ */
+ static final int FIXED = 3;
+
+ /**
+ * The type according to the constants of this class.
+ */
+ int type;
+
+ /**
+ * The left constraint, null if not set.
+ */
+ Length left;
+
+ /**
+ * The right constraint, null if not set.
+ */
+ Length right;
+
+ /**
+ * The top constraint, null if not set.
+ */
+ Length top;
+
+ /**
+ * The bottom constraint, null if not set.
+ */
+ Length bottom;
+
+ /**
+ * Creates a new PositionInfo object.
+ *
+ * @param typ the type to set
+ * @param l the left constraint
+ * @param r the right constraint
+ * @param t the top constraint
+ * @param b the bottom constraint
+ */
+ PositionInfo(int typ, Length l, Length r, Length t, Length b)
+ {
+ type = typ;
+ left = l;
+ right = r;
+ top = t;
+ bottom = b;
+ }
+ }
+
+ /**
+ * The attributes for this view.
+ */
+ private AttributeSet attributes;
+
+ /**
+ * The box painter for this view.
+ *
+ * This is package private because the TableView needs access to it.
+ */
+ StyleSheet.BoxPainter painter;
+
+ /**
+ * The width and height as specified in the stylesheet, null if not
+ * specified. The first value is the X_AXIS, the second the Y_AXIS. You
+ * can index this directly by the X_AXIS and Y_AXIS constants.
+ */
+ private Length[] cssSpans;
+
+ /**
+ * Stores additional CSS layout information.
+ */
+ private HashMap positionInfo;
+
+ /**
+ * Creates a new view that represents an html box.
+ * This can be used for a number of elements.
+ *
+ * @param elem - the element to create a view for
+ * @param axis - either View.X_AXIS or View.Y_AXIS
+ */
+ public BlockView(Element elem, int axis)
+ {
+ super(elem, axis);
+ cssSpans = new Length[2];
+ positionInfo = new HashMap();
+ }
+
+ /**
+ * Creates the parent view for this. It is called before
+ * any other methods, if the parent view is working properly.
+ * Implemented to forward to the superclass and call
+ * setPropertiesFromAttributes to set the paragraph
+ * properties.
+ *
+ * @param parent - the new parent, or null if the view
+ * is being removed from a parent it was added to.
+ */
+ public void setParent(View parent)
+ {
+ super.setParent(parent);
+
+ if (parent != null)
+ setPropertiesFromAttributes();
+ }
+
+ /**
+ * Calculates the requirements along the major axis.
+ * This is implemented to call the superclass and then
+ * adjust it if the CSS width or height attribute is specified
+ * and applicable.
+ *
+ * @param axis - the axis to check the requirements for.
+ * @param r - the SizeRequirements. If null, one is created.
+ * @return the new SizeRequirements object.
+ */
+ protected SizeRequirements calculateMajorAxisRequirements(int axis,
+ SizeRequirements r)
+ {
+ if (r == null)
+ r = new SizeRequirements();
+
+ if (setCSSSpan(r, axis))
+ {
+ // If we have set the span from CSS, then we need to adjust
+ // the margins.
+ SizeRequirements parent = super.calculateMajorAxisRequirements(axis,
+ null);
+ int margin = axis == X_AXIS ? getLeftInset() + getRightInset()
+ : getTopInset() + getBottomInset();
+ r.minimum -= margin;
+ r.preferred -= margin;
+ r.maximum -= margin;
+ constrainSize(axis, r, parent);
+ }
+ else
+ r = super.calculateMajorAxisRequirements(axis, r);
+ return r;
+ }
+
+ /**
+ * Calculates the requirements along the minor axis.
+ * This is implemented to call the superclass and then
+ * adjust it if the CSS width or height attribute is specified
+ * and applicable.
+ *
+ * @param axis - the axis to check the requirements for.
+ * @param r - the SizeRequirements. If null, one is created.
+ * @return the new SizeRequirements object.
+ */
+ protected SizeRequirements calculateMinorAxisRequirements(int axis,
+ SizeRequirements r)
+ {
+ if (r == null)
+ r = new SizeRequirements();
+
+ if (setCSSSpan(r, axis))
+ {
+ // If we have set the span from CSS, then we need to adjust
+ // the margins.
+ SizeRequirements parent = super.calculateMinorAxisRequirements(axis,
+ null);
+ int margin = axis == X_AXIS ? getLeftInset() + getRightInset()
+ : getTopInset() + getBottomInset();
+ r.minimum -= margin;
+ r.preferred -= margin;
+ r.maximum -= margin;
+ constrainSize(axis, r, parent);
+ }
+ else
+ r = super.calculateMinorAxisRequirements(axis, r);
+
+ // Apply text alignment if appropriate.
+ if (axis == X_AXIS)
+ {
+ Object o = getAttributes().getAttribute(CSS.Attribute.TEXT_ALIGN);
+ if (o != null)
+ {
+ String al = o.toString().trim();
+ if (al.equals("center"))
+ r.alignment = 0.5f;
+ else if (al.equals("right"))
+ r.alignment = 1.0f;
+ else
+ r.alignment = 0.0f;
+ }
+ }
+ return r;
+ }
+
+ /**
+ * Sets the span on the SizeRequirements object according to the
+ * according CSS span value, when it is set.
+ *
+ * @param r the size requirements
+ * @param axis the axis
+ *
+ * @return <code>true</code> when the CSS span has been set,
+ * <code>false</code> otherwise
+ */
+ private boolean setCSSSpan(SizeRequirements r, int axis)
+ {
+ boolean ret = false;
+ Length span = cssSpans[axis];
+ // We can't set relative CSS spans here because we don't know
+ // yet about the allocated span. Instead we use the view's
+ // normal requirements.
+ if (span != null && ! span.isPercentage())
+ {
+ r.minimum = (int) span.getValue();
+ r.preferred = (int) span.getValue();
+ r.maximum = (int) span.getValue();
+ ret = true;
+ }
+ return ret;
+ }
+
+ /**
+ * Constrains the <code>r</code> requirements according to
+ * <code>min</code>.
+ *
+ * @param axis the axis
+ * @param r the requirements to constrain
+ * @param min the constraining requirements
+ */
+ private void constrainSize(int axis, SizeRequirements r,
+ SizeRequirements min)
+ {
+ if (min.minimum > r.minimum)
+ {
+ r.minimum = min.minimum;
+ r.preferred = min.minimum;
+ r.maximum = Math.max(r.maximum, min.maximum);
+ }
+ }
+
+ /**
+ * Lays out the box along the minor axis (the axis that is
+ * perpendicular to the axis that it represents). The results
+ * of the layout are placed in the given arrays which are
+ * the allocations to the children along the minor axis.
+ *
+ * @param targetSpan - the total span given to the view, also
+ * used to layout the children.
+ * @param axis - the minor axis
+ * @param offsets - the offsets from the origin of the view for
+ * all the child views. This is a return value and is filled in by this
+ * function.
+ * @param spans - the span of each child view. This is a return value and is
+ * filled in by this function.
+ */
+ protected void layoutMinorAxis(int targetSpan, int axis,
+ int[] offsets, int[] spans)
+ {
+ int viewCount = getViewCount();
+ for (int i = 0; i < viewCount; i++)
+ {
+ View view = getView(i);
+ int min = (int) view.getMinimumSpan(axis);
+ int max;
+ // Handle CSS span value of child.
+ Length length = cssSpans[axis];
+ if (length != null)
+ {
+ min = Math.max((int) length.getValue(targetSpan), min);
+ max = min;
+ }
+ else
+ max = (int) view.getMaximumSpan(axis);
+
+ if (max < targetSpan)
+ {
+ // Align child.
+ float align = view.getAlignment(axis);
+ offsets[i] = (int) ((targetSpan - max) * align);
+ spans[i] = max;
+ }
+ else
+ {
+ offsets[i] = 0;
+ spans[i] = Math.max(min, targetSpan);
+ }
+
+ // Adjust according to CSS position info.
+ positionView(targetSpan, axis, i, offsets, spans);
+ }
+ }
+
+ /**
+ * Overridden to perform additional CSS layout (absolute/relative
+ * positioning).
+ */
+ protected void layoutMajorAxis(int targetSpan, int axis,
+ int[] offsets, int[] spans)
+ {
+ super.layoutMajorAxis(targetSpan, axis, offsets, spans);
+
+ // Adjust according to CSS position info.
+ int viewCount = getViewCount();
+ for (int i = 0; i < viewCount; i++)
+ {
+ positionView(targetSpan, axis, i, offsets, spans);
+ }
+ }
+
+ /**
+ * Positions a view according to any additional CSS constraints.
+ *
+ * @param targetSpan the target span
+ * @param axis the axis
+ * @param i the index of the view
+ * @param offsets the offsets get placed here
+ * @param spans the spans get placed here
+ */
+ private void positionView(int targetSpan, int axis, int i, int[] offsets,
+ int[] spans)
+ {
+ View view = getView(i);
+ PositionInfo pos = (PositionInfo) positionInfo.get(view);
+ if (pos != null)
+ {
+ int p0 = -1;
+ int p1 = -1;
+ if (axis == X_AXIS)
+ {
+ Length l = pos.left;
+ if (l != null)
+ p0 = (int) l.getValue(targetSpan);
+ l = pos.right;
+ if (l != null)
+ p1 = (int) l.getValue(targetSpan);
+ }
+ else
+ {
+ Length l = pos.top;
+ if (l != null)
+ p0 = (int) l.getValue(targetSpan);
+ l = pos.bottom;
+ if (l != null)
+ p1 = (int) l.getValue(targetSpan);
+ }
+ if (pos.type == PositionInfo.ABSOLUTE
+ || pos.type == PositionInfo.FIXED)
+ {
+ if (p0 != -1)
+ {
+ offsets[i] = p0;
+ if (p1 != -1)
+ {
+ // Overrides computed width. (Possibly overconstrained
+ // when the width attribute was set too.)
+ spans[i] = targetSpan - p1 - offsets[i];
+ }
+ }
+ else if (p1 != -1)
+ {
+ // Preserve any computed width.
+ offsets[i] = targetSpan - p1 - spans[i];
+ }
+ }
+ else if (pos.type == PositionInfo.RELATIVE)
+ {
+ if (p0 != -1)
+ {
+ offsets[i] += p0;
+ if (p1 != -1)
+ {
+ // Overrides computed width. (Possibly overconstrained
+ // when the width attribute was set too.)
+ spans[i] = spans[i] - p0 - p1 - offsets[i];
+ }
+ }
+ else if (p1 != -1)
+ {
+ // Preserve any computed width.
+ offsets[i] -= p1;
+ }
+ }
+ }
+ }
+
+ /**
+ * Paints using the given graphics configuration and shape.
+ * This delegates to the css box painter to paint the
+ * border and background prior to the interior.
+ *
+ * @param g - Graphics configuration
+ * @param a - the Shape to render into.
+ */
+ public void paint(Graphics g, Shape a)
+ {
+ Rectangle rect = a instanceof Rectangle ? (Rectangle) a : a.getBounds();
+
+ // Debug output. Shows blocks in green rectangles.
+ // g.setColor(Color.GREEN);
+ // g.drawRect(rect.x, rect.y, rect.width, rect.height);
+
+ painter.paint(g, rect.x, rect.y, rect.width, rect.height, this);
+ super.paint(g, a);
+ }
+
+ /**
+ * Fetches the attributes to use when painting.
+ *
+ * @return the attributes of this model.
+ */
+ public AttributeSet getAttributes()
+ {
+ if (attributes == null)
+ attributes = getStyleSheet().getViewAttributes(this);
+ return attributes;
+ }
+
+ /**
+ * Gets the resize weight.
+ *
+ * @param axis - the axis to get the resize weight for.
+ * @return the resize weight.
+ * @throws IllegalArgumentException - for an invalid axis
+ */
+ public int getResizeWeight(int axis) throws IllegalArgumentException
+ {
+ // Can't resize the Y_AXIS
+ if (axis == Y_AXIS)
+ return 0;
+ if (axis == X_AXIS)
+ return 1;
+ throw new IllegalArgumentException("Invalid Axis");
+ }
+
+ /**
+ * Gets the alignment.
+ *
+ * @param axis - the axis to get the alignment for.
+ * @return the alignment.
+ */
+ public float getAlignment(int axis)
+ {
+ if (axis == X_AXIS)
+ return super.getAlignment(axis);
+ if (axis == Y_AXIS)
+ {
+ if (getViewCount() == 0)
+ return 0.0F;
+ float prefHeight = getPreferredSpan(Y_AXIS);
+ View first = getView(0);
+ float firstRowHeight = first.getPreferredSpan(Y_AXIS);
+ return prefHeight != 0 ? (firstRowHeight * first.getAlignment(Y_AXIS))
+ / prefHeight
+ : 0;
+ }
+ throw new IllegalArgumentException("Invalid Axis");
+ }
+
+ /**
+ * Gives notification from the document that attributes were
+ * changed in a location that this view is responsible for.
+ *
+ * @param ev - the change information
+ * @param a - the current shape of the view
+ * @param f - the factory to use to rebuild if the view has children.
+ */
+ public void changedUpdate(DocumentEvent ev,
+ Shape a, ViewFactory f)
+ {
+ super.changedUpdate(ev, a, f);
+
+ // If more elements were added, then need to set the properties for them
+ int currPos = ev.getOffset();
+ if (currPos <= getStartOffset()
+ && (currPos + ev.getLength()) >= getEndOffset())
+ setPropertiesFromAttributes();
+ }
+
+ /**
+ * Determines the preferred span along the axis.
+ *
+ * @param axis - the view to get the preferred span for.
+ * @return the span the view would like to be painted into >=0/
+ * The view is usually told to paint into the span that is returned,
+ * although the parent may choose to resize or break the view.
+ * @throws IllegalArgumentException - for an invalid axis
+ */
+ public float getPreferredSpan(int axis) throws IllegalArgumentException
+ {
+ if (axis == X_AXIS || axis == Y_AXIS)
+ return super.getPreferredSpan(axis);
+ throw new IllegalArgumentException("Invalid Axis");
+ }
+
+ /**
+ * Determines the minimum span along the axis.
+ *
+ * @param axis - the axis to get the minimum span for.
+ * @return the span the view would like to be painted into >=0/
+ * The view is usually told to paint into the span that is returned,
+ * although the parent may choose to resize or break the view.
+ * @throws IllegalArgumentException - for an invalid axis
+ */
+ public float getMinimumSpan(int axis) throws IllegalArgumentException
+ {
+ if (axis == X_AXIS || axis == Y_AXIS)
+ return super.getMinimumSpan(axis);
+ throw new IllegalArgumentException("Invalid Axis");
+ }
+
+ /**
+ * Determines the maximum span along the axis.
+ *
+ * @param axis - the axis to get the maximum span for.
+ * @return the span the view would like to be painted into >=0/
+ * The view is usually told to paint into the span that is returned,
+ * although the parent may choose to resize or break the view.
+ * @throws IllegalArgumentException - for an invalid axis
+ */
+ public float getMaximumSpan(int axis) throws IllegalArgumentException
+ {
+ if (axis == X_AXIS || axis == Y_AXIS)
+ return super.getMaximumSpan(axis);
+ throw new IllegalArgumentException("Invalid Axis");
+ }
+
+ /**
+ * Updates any cached values that come from attributes.
+ */
+ protected void setPropertiesFromAttributes()
+ {
+ // Fetch attributes.
+ StyleSheet ss = getStyleSheet();
+ attributes = ss.getViewAttributes(this);
+
+ // Fetch painter.
+ painter = ss.getBoxPainter(attributes);
+
+ // Update insets.
+ if (attributes != null)
+ {
+ setInsets((short) painter.getInset(TOP, this),
+ (short) painter.getInset(LEFT, this),
+ (short) painter.getInset(BOTTOM, this),
+ (short) painter.getInset(RIGHT, this));
+ }
+
+ // Fetch width and height.
+ float emBase = ss.getEMBase(attributes);
+ float exBase = ss.getEXBase(attributes);
+ cssSpans[X_AXIS] = (Length) attributes.getAttribute(CSS.Attribute.WIDTH);
+ if (cssSpans[X_AXIS] != null)
+ cssSpans[X_AXIS].setFontBases(emBase, exBase);
+ cssSpans[Y_AXIS] = (Length) attributes.getAttribute(CSS.Attribute.HEIGHT);
+ if (cssSpans[Y_AXIS] != null)
+ cssSpans[Y_AXIS].setFontBases(emBase, exBase);
+ }
+
+ /**
+ * Gets the default style sheet.
+ *
+ * @return the style sheet
+ */
+ protected StyleSheet getStyleSheet()
+ {
+ HTMLDocument doc = (HTMLDocument) getDocument();
+ return doc.getStyleSheet();
+ }
+
+ /**
+ * Overridden to fetch additional CSS layout information.
+ */
+ public void replace(int offset, int length, View[] views)
+ {
+ // First remove unneeded stuff.
+ for (int i = 0; i < length; i++)
+ {
+ View child = getView(i + offset);
+ positionInfo.remove(child);
+ }
+
+ // Call super to actually replace the views.
+ super.replace(offset, length, views);
+
+ // Now fetch the position infos for the new views.
+ for (int i = 0; i < views.length; i++)
+ {
+ fetchLayoutInfo(views[i]);
+ }
+ }
+
+ /**
+ * Fetches and stores the layout info for the specified view.
+ *
+ * @param view the view for which the layout info is stored
+ */
+ private void fetchLayoutInfo(View view)
+ {
+ AttributeSet atts = view.getAttributes();
+ Object o = atts.getAttribute(CSS.Attribute.POSITION);
+ if (o != null && o instanceof String && ! o.equals("static"))
+ {
+ int type;
+ if (o.equals("relative"))
+ type = PositionInfo.RELATIVE;
+ else if (o.equals("absolute"))
+ type = PositionInfo.ABSOLUTE;
+ else if (o.equals("fixed"))
+ type = PositionInfo.FIXED;
+ else
+ type = PositionInfo.STATIC;
+
+ if (type != PositionInfo.STATIC)
+ {
+ StyleSheet ss = getStyleSheet();
+ float emBase = ss.getEMBase(atts);
+ float exBase = ss.getEXBase(atts);
+ Length left = (Length) atts.getAttribute(CSS.Attribute.LEFT);
+ if (left != null)
+ left.setFontBases(emBase, exBase);
+ Length right = (Length) atts.getAttribute(CSS.Attribute.RIGHT);
+ if (right != null)
+ right.setFontBases(emBase, exBase);
+ Length top = (Length) atts.getAttribute(CSS.Attribute.TOP);
+ if (top != null)
+ top.setFontBases(emBase, exBase);
+ Length bottom = (Length) atts.getAttribute(CSS.Attribute.BOTTOM);
+ if (bottom != null)
+ bottom.setFontBases(emBase, exBase);
+ if (left != null || right != null || top != null || bottom != null)
+ {
+ PositionInfo pos = new PositionInfo(type, left, right, top,
+ bottom);
+ positionInfo.put(view, pos);
+ }
+ }
+ }
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/CSS.java b/libjava/classpath/javax/swing/text/html/CSS.java
new file mode 100644
index 000000000..0a77bdff9
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/CSS.java
@@ -0,0 +1,736 @@
+/* CSS.java -- Provides CSS attributes
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import gnu.javax.swing.text.html.css.BorderStyle;
+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
+ * {@link javax.swing.text.AttributeSet}s of {@link javax.swing.text.Element}s.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class CSS implements Serializable
+{
+ /**
+ * Returns an array of all CSS attributes.
+ *
+ * @return All available CSS.Attribute objects.
+ */
+ public static CSS.Attribute[] getAllAttributeKeys()
+ {
+ Object[] src = Attribute.attributeMap.values().toArray();
+ CSS.Attribute[] dst = new CSS.Attribute[ src.length ];
+ System.arraycopy(src, 0, dst, 0, src.length);
+ return dst;
+ }
+
+ /**
+ * Returns an a given CSS attribute.
+ *
+ * @param name - The name of the attribute.
+ * @return The CSS attribute with the given name, or <code>null</code> if
+ * no attribute with that name exists.
+ */
+ public static CSS.Attribute getAttribute(String name)
+ {
+ return (CSS.Attribute)Attribute.attributeMap.get( name );
+ }
+
+ public static final class Attribute
+ {
+ /**
+ * The CSS attribute 'background'.
+ */
+ public static final Attribute BACKGROUND =
+ new Attribute("background", false, null);
+
+ /**
+ * The CSS attribute 'background-attachment'.
+ */
+ public static final Attribute BACKGROUND_ATTACHMENT =
+ new Attribute("background-attachment", false, "scroll");
+
+ /**
+ * The CSS attribute 'background-color'.
+ */
+ public static final Attribute BACKGROUND_COLOR =
+ new Attribute("background-color", false, "transparent");
+
+ /**
+ * The CSS attribute 'background-image'.
+ */
+ public static final Attribute BACKGROUND_IMAGE =
+ new Attribute("background-image", false, "none");
+
+ /**
+ * The CSS attribute 'background-position'.
+ */
+ public static final Attribute BACKGROUND_POSITION =
+ new Attribute("background-position", false, null);
+
+ /**
+ * The CSS attribute 'background-repeat'.
+ */
+ public static final Attribute BACKGROUND_REPEAT =
+ new Attribute("background-repeat", false, "repeat");
+
+ /**
+ * The CSS attribute 'border'.
+ */
+ public static final Attribute BORDER = new Attribute("border", false, null);
+
+ /**
+ * The CSS attribute 'border-bottom'.
+ */
+ public static final Attribute BORDER_BOTTOM =
+ new Attribute("border-bottom", false, null);
+
+ /**
+ * The CSS attribute 'border-bottom-width'.
+ */
+ public static final Attribute BORDER_BOTTOM_WIDTH =
+ new Attribute("border-bottom-width", false, "medium");
+
+ /**
+ * The CSS attribute 'border-color'.
+ */
+ public static final Attribute BORDER_COLOR =
+ new Attribute("border-color", false, "black");
+
+ /**
+ * The CSS attribute 'border-left'.
+ */
+ public static final Attribute BORDER_LEFT =
+ new Attribute("border-left", false, null);
+
+ /**
+ * The CSS attribute 'border-left-width'.
+ */
+ public static final Attribute BORDER_LEFT_WIDTH =
+ new Attribute("border-left-width", false, "medium");
+
+ /**
+ * The CSS attribute 'border-right'.
+ */
+ public static final Attribute BORDER_RIGHT =
+ new Attribute("border-right", false, null);
+
+ /**
+ * The CSS attribute 'border-right-width'.
+ */
+ public static final Attribute BORDER_RIGHT_WIDTH =
+ new Attribute("border-right-width", false, "medium");
+
+ /**
+ * The CSS attribute 'border-style'.
+ */
+ public static final Attribute BORDER_STYLE =
+ new Attribute("border-style", false, "none");
+
+ /**
+ * The CSS attribute 'border-top'.
+ */
+ public static final Attribute BORDER_TOP =
+ new Attribute("border-top", false, null);
+
+ /**
+ * The CSS attribute 'border-top-width'.
+ */
+ public static final Attribute BORDER_TOP_WIDTH =
+ new Attribute("border-top-width", false, "medium");
+
+ /**
+ * The CSS attribute 'border-width'.
+ */
+ public static final Attribute BORDER_WIDTH =
+ new Attribute("border-width", false, "medium");
+
+ /**
+ * The CSS attribute 'clear'.
+ */
+ public static final Attribute CLEAR = new Attribute("clear", false, "none");
+
+ /**
+ * The CSS attribute 'color'.
+ */
+ public static final Attribute COLOR = new Attribute("color", true, "black");
+
+ /**
+ * The CSS attribute 'display'.
+ */
+ public static final Attribute DISPLAY =
+ new Attribute("display", false, "block");
+
+ /**
+ * The CSS attribute 'float'.
+ */
+ public static final Attribute FLOAT = new Attribute("float", false, "none");
+
+ /**
+ * The CSS attribute 'font'.
+ */
+ public static final Attribute FONT = new Attribute("font", true, null);
+
+ /**
+ * The CSS attribute 'font-family'.
+ */
+ public static final Attribute FONT_FAMILY =
+ new Attribute("font-family", true, null);
+
+ /**
+ * The CSS attribute 'font-size'.
+ */
+ public static final Attribute FONT_SIZE =
+ new Attribute("font-size", true, "medium");
+
+ /**
+ * The CSS attribute 'font-style'.
+ */
+ public static final Attribute FONT_STYLE =
+ new Attribute("font-style", true, "normal");
+
+ /**
+ * The CSS attribute 'font-variant'.
+ */
+ public static final Attribute FONT_VARIANT =
+ new Attribute("font-variant", true, "normal");
+
+ /**
+ * The CSS attribute 'font-weight'.
+ */
+ public static final Attribute FONT_WEIGHT =
+ new Attribute("font-weight", true, "normal");
+
+ /**
+ * The CSS attribute 'height'.
+ */
+ public static final Attribute HEIGHT =
+ new Attribute("height", false, "auto");
+
+ /**
+ * The CSS attribute 'letter-spacing'.
+ */
+ public static final Attribute LETTER_SPACING =
+ new Attribute("letter-spacing", true, "normal");
+
+ /**
+ * The CSS attribute 'line-height'.
+ */
+ public static final Attribute LINE_HEIGHT =
+ new Attribute("line-height", true, "normal");
+
+ /**
+ * The CSS attribute 'list-style'.
+ */
+ public static final Attribute LIST_STYLE =
+ new Attribute("list-style", true, null);
+
+ /**
+ * The CSS attribute 'list-style-image'.
+ */
+ public static final Attribute LIST_STYLE_IMAGE =
+ new Attribute("list-style-image", true, "none");
+
+ /**
+ * The CSS attribute 'list-style-position'.
+ */
+ public static final Attribute LIST_STYLE_POSITION =
+ new Attribute("list-style-position", true, "outside");
+
+ /**
+ * The CSS attribute 'list-style-type'.
+ */
+ public static final Attribute LIST_STYLE_TYPE =
+ new Attribute("list-style-type", true, "disc");
+
+ /**
+ * The CSS attribute 'margin'.
+ */
+ public static final Attribute MARGIN = new Attribute("margin", false, null);
+
+ /**
+ * The CSS attribute 'margin-bottom'.
+ */
+ public static final Attribute MARGIN_BOTTOM =
+ new Attribute("margin-bottom", false, "0");
+
+ /**
+ * The CSS attribute 'margin-left'.
+ */
+ public static final Attribute MARGIN_LEFT =
+ new Attribute("margin-left", false, "0");
+
+ /**
+ * The CSS attribute 'margin-right'.
+ */
+ public static final Attribute MARGIN_RIGHT =
+ new Attribute("margin-right", false, "0");
+
+ /**
+ * The CSS attribute 'margin-top'.
+ */
+ public static final Attribute MARGIN_TOP =
+ new Attribute("margin-top", false, "0");
+
+ /**
+ * The CSS attribute 'padding'.
+ */
+ public static final Attribute PADDING =
+ new Attribute("padding", false, null);
+
+ /**
+ * The CSS attribute 'padding-bottom'.
+ */
+ public static final Attribute PADDING_BOTTOM =
+ new Attribute("padding-bottom", false, "0");
+
+ /**
+ * The CSS attribute 'padding-left'.
+ */
+ public static final Attribute PADDING_LEFT =
+ new Attribute("padding-left", false, "0");
+
+ /**
+ * The CSS attribute 'padding-right'.
+ */
+ public static final Attribute PADDING_RIGHT =
+ new Attribute("padding-right", false, "0");
+
+ /**
+ * The CSS attribute 'padding-top'.
+ */
+ public static final Attribute PADDING_TOP =
+ new Attribute("padding-top", false, "0");
+
+ /**
+ * The CSS attribute 'text-align'.
+ */
+ public static final Attribute TEXT_ALIGN =
+ new Attribute("text-align", true, null);
+
+ /**
+ * The CSS attribute 'text-decoration'.
+ */
+ public static final Attribute TEXT_DECORATION =
+ new Attribute("text-decoration", true, "none");
+
+ /**
+ * The CSS attribute 'text-indent'.
+ */
+ public static final Attribute TEXT_INDENT =
+ new Attribute("text-indent", true, "0");
+
+ /**
+ * The CSS attribute 'text-transform'.
+ */
+ public static final Attribute TEXT_TRANSFORM =
+ new Attribute("text-transform", true, "none");
+
+ /**
+ * The CSS attribute 'vertical-align'.
+ */
+ public static final Attribute VERTICAL_ALIGN =
+ new Attribute("vertical-align", false, "baseline");
+
+ /**
+ * The CSS attribute 'white-space'.
+ */
+ public static final Attribute WHITE_SPACE =
+ new Attribute("white-space", true, "normal");
+
+ /**
+ * The CSS attribute 'width'.
+ */
+ public static final Attribute WIDTH =
+ new Attribute("width", false, "auto");
+
+ /**
+ * The CSS attribute 'word-spacing'.
+ */
+ public static final Attribute WORD_SPACING =
+ new Attribute("word-spacing", true, "normal");
+
+ // Some GNU Classpath specific extensions.
+ static final Attribute BORDER_TOP_STYLE =
+ new Attribute("border-top-style", false, null);
+ static final Attribute BORDER_BOTTOM_STYLE =
+ new Attribute("border-bottom-style", false, null);
+ static final Attribute BORDER_LEFT_STYLE =
+ new Attribute("border-left-style", false, null);
+ static final Attribute BORDER_RIGHT_STYLE =
+ new Attribute("border-right-style", false, null);
+ static final Attribute BORDER_TOP_COLOR =
+ new Attribute("border-top-color", false, null);
+ static final Attribute BORDER_BOTTOM_COLOR =
+ new Attribute("border-bottom-color", false, null);
+ static final Attribute BORDER_LEFT_COLOR =
+ new Attribute("border-left-color", false, null);
+ static final Attribute BORDER_RIGHT_COLOR =
+ new Attribute("border-right-color", false, null);
+ static final Attribute BORDER_SPACING =
+ new Attribute("border-spacing", false, null);
+ static final Attribute POSITION =
+ new Attribute("position", false, null);
+ static final Attribute LEFT =
+ new Attribute("left", false, null);
+ static final Attribute RIGHT =
+ new Attribute("right", false, null);
+ static final Attribute TOP =
+ new Attribute("top", false, null);
+ static final Attribute BOTTOM =
+ new Attribute("bottom", false, null);
+
+ /**
+ * The attribute string.
+ */
+ String attStr;
+
+ /**
+ * Indicates if this attribute should be inherited from it's parent or
+ * not.
+ */
+ boolean isInherited;
+
+ /**
+ * A default value for this attribute if one exists, otherwise null.
+ */
+ String defaultValue;
+
+ /**
+ * A HashMap of all attributes.
+ */
+ static HashMap attributeMap;
+
+ /**
+ * Creates a new Attribute instance with the specified values.
+ *
+ * @param attr the attribute string
+ * @param inherited if the attribute should be inherited or not
+ * @param def a default value; may be <code>null</code>
+ */
+ Attribute(String attr, boolean inherited, String def)
+ {
+ attStr = attr;
+ isInherited = inherited;
+ defaultValue = def;
+ if( attributeMap == null)
+ attributeMap = new HashMap();
+ attributeMap.put( attr, this );
+ }
+
+ /**
+ * Returns the string representation of this attribute as specified
+ * in the CSS specification.
+ */
+ public String toString()
+ {
+ return attStr;
+ }
+
+ /**
+ * Returns <code>true</code> if the attribute should be inherited from
+ * the parent, <code>false</code> otherwise.
+ *
+ * @return <code>true</code> if the attribute should be inherited from
+ * the parent, <code>false</code> otherwise
+ */
+ public boolean isInherited()
+ {
+ return isInherited;
+ }
+
+ /**
+ * Returns the default value of this attribute if one exists,
+ * <code>null</code> otherwise.
+ *
+ * @return the default value of this attribute if one exists,
+ * <code>null</code> otherwise
+ */
+ public String getDefaultValue()
+ {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Maps attribute values (String) to some converter class, based on the
+ * key.
+ *
+ * @param att the key
+ * @param v the value
+ *
+ * @return the wrapped value
+ */
+ static Object getValue(Attribute att, String v)
+ {
+ Object o;
+ if (att == Attribute.FONT_SIZE)
+ o = new FontSize(v);
+ else if (att == Attribute.FONT_WEIGHT)
+ o = new FontWeight(v);
+ else if (att == Attribute.FONT_STYLE)
+ o = new FontStyle(v);
+ else if (att == Attribute.COLOR || att == Attribute.BACKGROUND_COLOR
+ || att == Attribute.BORDER_COLOR
+ || att == Attribute.BORDER_TOP_COLOR
+ || att == Attribute.BORDER_BOTTOM_COLOR
+ || att == Attribute.BORDER_LEFT_COLOR
+ || att == Attribute.BORDER_RIGHT_COLOR)
+ 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
+ || att == Attribute.PADDING || att == Attribute.PADDING_BOTTOM
+ || att == Attribute.PADDING_LEFT || att == Attribute.PADDING_RIGHT
+ || att == Attribute.PADDING_TOP
+ || att == Attribute.LEFT || att == Attribute.RIGHT
+ || att == Attribute.TOP || att == Attribute.BOTTOM)
+ 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);
+ else if (a == Attribute.PADDING)
+ parsePaddingShorthand(atts, v);
+ else if (a == Attribute.MARGIN)
+ parseMarginShorthand(atts, v);
+ else if (a == Attribute.BORDER || a == Attribute.BORDER_LEFT
+ || a == Attribute.BORDER_RIGHT || a == Attribute.BORDER_TOP
+ || a == Attribute.BORDER_BOTTOM)
+ parseBorderShorthand(atts, v, a);
+ }
+
+ /**
+ * Parses the background shorthand and translates it to more specific
+ * background attributes.
+ *
+ * @param atts the attributes
+ * @param v the value
+ */
+ 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,
+ new CSSColor(token));
+ }
+ }
+
+ /**
+ * Parses the padding shorthand and translates to the specific padding
+ * values.
+ *
+ * @param atts the attributes
+ * @param v the actual value
+ */
+ private static void parsePaddingShorthand(MutableAttributeSet atts, String v)
+ {
+ StringTokenizer tokens = new StringTokenizer(v, " ");
+ int numTokens = tokens.countTokens();
+ if (numTokens == 1)
+ {
+ Length l = new Length(tokens.nextToken());
+ atts.addAttribute(Attribute.PADDING_BOTTOM, l);
+ atts.addAttribute(Attribute.PADDING_LEFT, l);
+ atts.addAttribute(Attribute.PADDING_RIGHT, l);
+ atts.addAttribute(Attribute.PADDING_TOP, l);
+ }
+ else if (numTokens == 2)
+ {
+ Length l1 = new Length(tokens.nextToken());
+ Length l2 = new Length(tokens.nextToken());
+ atts.addAttribute(Attribute.PADDING_BOTTOM, l1);
+ atts.addAttribute(Attribute.PADDING_TOP, l1);
+ atts.addAttribute(Attribute.PADDING_LEFT, l2);
+ atts.addAttribute(Attribute.PADDING_RIGHT, l2);
+ }
+ else if (numTokens == 3)
+ {
+ Length l1 = new Length(tokens.nextToken());
+ Length l2 = new Length(tokens.nextToken());
+ Length l3 = new Length(tokens.nextToken());
+ atts.addAttribute(Attribute.PADDING_TOP, l1);
+ atts.addAttribute(Attribute.PADDING_LEFT, l2);
+ atts.addAttribute(Attribute.PADDING_RIGHT, l2);
+ atts.addAttribute(Attribute.PADDING_BOTTOM, l3);
+ }
+ else
+ {
+ Length l1 = new Length(tokens.nextToken());
+ Length l2 = new Length(tokens.nextToken());
+ Length l3 = new Length(tokens.nextToken());
+ Length l4 = new Length(tokens.nextToken());
+ atts.addAttribute(Attribute.PADDING_TOP, l1);
+ atts.addAttribute(Attribute.PADDING_RIGHT, l2);
+ atts.addAttribute(Attribute.PADDING_BOTTOM, l3);
+ atts.addAttribute(Attribute.PADDING_LEFT, l4);
+ }
+ }
+
+ /**
+ * Parses the margin shorthand and translates to the specific margin
+ * values.
+ *
+ * @param atts the attributes
+ * @param v the actual value
+ */
+ private static void parseMarginShorthand(MutableAttributeSet atts, String v)
+ {
+ StringTokenizer tokens = new StringTokenizer(v, " ");
+ int numTokens = tokens.countTokens();
+ if (numTokens == 1)
+ {
+ Length l = new Length(tokens.nextToken());
+ atts.addAttribute(Attribute.MARGIN_BOTTOM, l);
+ atts.addAttribute(Attribute.MARGIN_LEFT, l);
+ atts.addAttribute(Attribute.MARGIN_RIGHT, l);
+ atts.addAttribute(Attribute.MARGIN_TOP, l);
+ }
+ else if (numTokens == 2)
+ {
+ Length l1 = new Length(tokens.nextToken());
+ Length l2 = new Length(tokens.nextToken());
+ atts.addAttribute(Attribute.MARGIN_BOTTOM, l1);
+ atts.addAttribute(Attribute.MARGIN_TOP, l1);
+ atts.addAttribute(Attribute.MARGIN_LEFT, l2);
+ atts.addAttribute(Attribute.MARGIN_RIGHT, l2);
+ }
+ else if (numTokens == 3)
+ {
+ Length l1 = new Length(tokens.nextToken());
+ Length l2 = new Length(tokens.nextToken());
+ Length l3 = new Length(tokens.nextToken());
+ atts.addAttribute(Attribute.MARGIN_TOP, l1);
+ atts.addAttribute(Attribute.MARGIN_LEFT, l2);
+ atts.addAttribute(Attribute.MARGIN_RIGHT, l2);
+ atts.addAttribute(Attribute.MARGIN_BOTTOM, l3);
+ }
+ else
+ {
+ Length l1 = new Length(tokens.nextToken());
+ Length l2 = new Length(tokens.nextToken());
+ Length l3 = new Length(tokens.nextToken());
+ Length l4 = new Length(tokens.nextToken());
+ atts.addAttribute(Attribute.MARGIN_TOP, l1);
+ atts.addAttribute(Attribute.MARGIN_RIGHT, l2);
+ atts.addAttribute(Attribute.MARGIN_BOTTOM, l3);
+ atts.addAttribute(Attribute.MARGIN_LEFT, l4);
+ }
+ }
+
+ /**
+ * Parses the CSS border shorthand attribute and translates it to the
+ * more specific border attributes.
+ *
+ * @param atts the attribute
+ * @param value the value
+ */
+ private static void parseBorderShorthand(MutableAttributeSet atts,
+ String value, Attribute cssAtt)
+ {
+ StringTokenizer tokens = new StringTokenizer(value, " ");
+ while (tokens.hasMoreTokens())
+ {
+ String token = tokens.nextToken();
+ if (BorderStyle.isValidStyle(token))
+ {
+ if (cssAtt == Attribute.BORDER_LEFT || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_LEFT_STYLE, token);
+ if (cssAtt == Attribute.BORDER_RIGHT || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_RIGHT_STYLE, token);
+ if (cssAtt == Attribute.BORDER_BOTTOM || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_BOTTOM_STYLE, token);
+ if (cssAtt == Attribute.BORDER_TOP || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_TOP_STYLE, token);
+ }
+ else if (BorderWidth.isValid(token))
+ {
+ BorderWidth w = new BorderWidth(token);
+ if (cssAtt == Attribute.BORDER_LEFT || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_LEFT_WIDTH, w);
+ if (cssAtt == Attribute.BORDER_RIGHT || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_RIGHT_WIDTH, w);
+ if (cssAtt == Attribute.BORDER_BOTTOM || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_BOTTOM_WIDTH, w);
+ if (cssAtt == Attribute.BORDER_TOP || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_TOP_WIDTH, w);
+ }
+ else if (CSSColor.isValidColor(token))
+ {
+ CSSColor c = new CSSColor(token);
+ if (cssAtt == Attribute.BORDER_LEFT || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_LEFT_COLOR, c);
+ if (cssAtt == Attribute.BORDER_RIGHT || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_RIGHT_COLOR, c);
+ if (cssAtt == Attribute.BORDER_BOTTOM || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_BOTTOM_COLOR, c);
+ if (cssAtt == Attribute.BORDER_TOP || cssAtt == Attribute.BORDER)
+ atts.addAttribute(Attribute.BORDER_TOP_COLOR, c);
+ }
+ }
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/CSSBorder.java b/libjava/classpath/javax/swing/text/html/CSSBorder.java
new file mode 100644
index 000000000..23fcdccc6
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/CSSBorder.java
@@ -0,0 +1,421 @@
+/* CSSBorder.java -- A border for rendering CSS border styles
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import gnu.javax.swing.text.html.css.BorderWidth;
+import gnu.javax.swing.text.html.css.CSSColor;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Insets;
+
+import javax.swing.border.Border;
+import javax.swing.text.AttributeSet;
+
+/**
+ * A border implementation to render CSS border styles.
+ */
+class CSSBorder
+ implements Border
+{
+
+ /**
+ * The CSS border styles.
+ */
+
+ private static final int STYLE_NOT_SET = -1;
+ private static final int STYLE_NONE = 0;
+ private static final int STYLE_HIDDEN = 1;
+ private static final int STYLE_DOTTED = 2;
+ private static final int STYLE_DASHED = 3;
+ private static final int STYLE_SOLID = 4;
+ private static final int STYLE_DOUBLE = 5;
+ private static final int STYLE_GROOVE = 6;
+ private static final int STYLE_RIDGE = 7;
+ private static final int STYLE_INSET = 8;
+ private static final int STYLE_OUTSET = 9;
+
+ /**
+ * The left insets.
+ */
+ private int left;
+
+ /**
+ * The right insets.
+ */
+ private int right;
+
+ /**
+ * The top insets.
+ */
+ private int top;
+
+ /**
+ * The bottom insets.
+ */
+ private int bottom;
+
+ /**
+ * The border style on the left.
+ */
+ private int leftStyle;
+
+ /**
+ * The border style on the right.
+ */
+ private int rightStyle;
+
+ /**
+ * The border style on the top.
+ */
+ private int topStyle;
+
+ /**
+ * The color for the top border.
+ */
+ private Color topColor;
+
+ /**
+ * The color for the bottom border.
+ */
+ private Color bottomColor;
+
+ /**
+ * The color for the left border.
+ */
+ private Color leftColor;
+
+ /**
+ * The color for the right border.
+ */
+ private Color rightColor;
+
+ /**
+ * The border style on the bottom.
+ */
+ private int bottomStyle;
+
+ /**
+ * Creates a new CSS border and fetches its attributes from the specified
+ * attribute set.
+ *
+ * @param atts the attribute set that contains the border spec
+ */
+ CSSBorder(AttributeSet atts, StyleSheet ss)
+ {
+ // Determine the border styles.
+ int style = getBorderStyle(atts, CSS.Attribute.BORDER_STYLE);
+ if (style == STYLE_NOT_SET)
+ style = STYLE_NONE; // Default to none.
+ topStyle = bottomStyle = leftStyle = rightStyle = style;
+ style = getBorderStyle(atts, CSS.Attribute.BORDER_TOP_STYLE);
+ if (style != STYLE_NOT_SET)
+ topStyle = style;
+ style = getBorderStyle(atts, CSS.Attribute.BORDER_BOTTOM_STYLE);
+ if (style != STYLE_NOT_SET)
+ bottomStyle = style;
+ style = getBorderStyle(atts, CSS.Attribute.BORDER_LEFT_STYLE);
+ if (style != STYLE_NOT_SET)
+ leftStyle = style;
+ style = getBorderStyle(atts, CSS.Attribute.BORDER_RIGHT_STYLE);
+ if (style != STYLE_NOT_SET)
+ rightStyle = style;
+
+ // Determine the border colors.
+ Color color = getBorderColor(atts, CSS.Attribute.BORDER_COLOR);
+ if (color == null)
+ color = Color.BLACK;
+ topColor = bottomColor = leftColor = rightColor = color;
+ color = getBorderColor(atts, CSS.Attribute.BORDER_TOP_COLOR);
+ if (color != null)
+ topColor = color;
+ color = getBorderColor(atts, CSS.Attribute.BORDER_BOTTOM_COLOR);
+ if (color != null)
+ bottomColor = color;
+ color = getBorderColor(atts, CSS.Attribute.BORDER_LEFT_COLOR);
+ if (color != null)
+ leftColor = color;
+ color = getBorderColor(atts, CSS.Attribute.BORDER_RIGHT_COLOR);
+ if (color != null)
+ rightColor = color;
+
+ // Determine the border widths.
+ int width = getBorderWidth(atts, CSS.Attribute.BORDER_WIDTH, ss);
+ if (width == -1)
+ width = 0;
+ top = bottom = left = right = width;
+ width = getBorderWidth(atts, CSS.Attribute.BORDER_TOP_WIDTH, ss);
+ if (width >= 0)
+ top = width;
+ width = getBorderWidth(atts, CSS.Attribute.BORDER_BOTTOM_WIDTH, ss);
+ if (width >= 0)
+ bottom = width;
+ width = getBorderWidth(atts, CSS.Attribute.BORDER_LEFT_WIDTH, ss);
+ if (width >= 0)
+ left = width;
+ width = getBorderWidth(atts, CSS.Attribute.BORDER_RIGHT_WIDTH, ss);
+ if (width >= 0)
+ right = width;
+ }
+
+ /**
+ * Determines the border style for a given CSS attribute.
+ *
+ * @param atts the attribute set
+ * @param key the CSS key
+ *
+ * @return the border style according to the constants defined in this class
+ */
+ private int getBorderStyle(AttributeSet atts, CSS.Attribute key)
+ {
+ int style = STYLE_NOT_SET;
+ Object o = atts.getAttribute(key);
+ if (o != null)
+ {
+ String cssStyle = o.toString();
+ if (cssStyle.equals("none"))
+ style = STYLE_NONE;
+ else if (cssStyle.equals("hidden"))
+ style = STYLE_HIDDEN;
+ else if (cssStyle.equals("dotted"))
+ style = STYLE_DOTTED;
+ else if (cssStyle.equals("dashed"))
+ style = STYLE_DASHED;
+ else if (cssStyle.equals("solid"))
+ style = STYLE_SOLID;
+ else if (cssStyle.equals("double"))
+ style = STYLE_DOUBLE;
+ else if (cssStyle.equals("groove"))
+ style = STYLE_GROOVE;
+ else if (cssStyle.equals("ridge"))
+ style = STYLE_RIDGE;
+ else if (cssStyle.equals("inset"))
+ style = STYLE_INSET;
+ else if (cssStyle.equals("outset"))
+ style = STYLE_OUTSET;
+ }
+ return style;
+ }
+
+ /**
+ * Determines the border color for the specified key.
+ *
+ * @param atts the attribute set from which to fetch the color
+ * @param key the CSS key
+ *
+ * @return the border color
+ */
+ private Color getBorderColor(AttributeSet atts, CSS.Attribute key)
+ {
+ Object o = atts.getAttribute(key);
+ Color color = null;
+ if (o instanceof CSSColor)
+ {
+ CSSColor cssColor = (CSSColor) o;
+ color = cssColor.getValue();
+ }
+ return color;
+ }
+
+ /**
+ * Returns the width for the specified key.
+ *
+ * @param atts the attributes to fetch the width from
+ * @param key the CSS key
+ *
+ * @return the width, or -1 of none has been set
+ */
+ private int getBorderWidth(AttributeSet atts, CSS.Attribute key,
+ StyleSheet ss)
+ {
+ int width = -1;
+ Object o = atts.getAttribute(key);
+ if (o instanceof BorderWidth)
+ {
+ BorderWidth w = (BorderWidth) o;
+ w.setFontBases(ss.getEMBase(atts), ss.getEXBase(atts));
+ width = (int) ((BorderWidth) o).getValue();
+ }
+ return width;
+ }
+
+ /**
+ * Returns the border insets.
+ */
+ public Insets getBorderInsets(Component c)
+ {
+ return new Insets(top, left, bottom, right);
+ }
+
+ /**
+ * CSS borders are generally opaque so return true here.
+ */
+ public boolean isBorderOpaque()
+ {
+ return true;
+ }
+
+ public void paintBorder(Component c, Graphics g, int x, int y, int width,
+ int height)
+ {
+ // Top border.
+ paintBorderLine(g, x, y + top / 2, x + width, y + top / 2, topStyle, top,
+ topColor, false);
+ // Left border.
+ paintBorderLine(g, x + left / 2, y, x + left / 2, y + height, leftStyle,
+ left, leftColor, true);
+ // Bottom border.
+ paintBorderLine(g, x, y + height - bottom / 2, x + width,
+ y + height - bottom / 2, topStyle, bottom, bottomColor,
+ false);
+ // Right border.
+ paintBorderLine(g, x + width - right / 2, y, x + width - right / 2,
+ y + height, topStyle, right, rightColor, true);
+
+ }
+
+ private void paintBorderLine(Graphics g, int x1, int y1, int x2, int y2,
+ int style, int width, Color color,
+ boolean vertical)
+ {
+ switch (style)
+ {
+ case STYLE_DOTTED:
+ paintDottedLine(g, x1, y1, x2, y2, width, color, vertical);
+ break;
+ case STYLE_DASHED:
+ paintDashedLine(g, x1, y1, x2, y2, width, color, vertical);
+ break;
+ case STYLE_SOLID:
+ paintSolidLine(g, x1, y1, x2, y2, width, color, vertical);
+ break;
+ case STYLE_DOUBLE:
+ paintDoubleLine(g, x1, y1, x2, y2, width, color, vertical);
+ break;
+ case STYLE_GROOVE:
+ paintGrooveLine(g, x1, y1, x2, y2, width, color, vertical);
+ break;
+ case STYLE_RIDGE:
+ paintRidgeLine(g, x1, y1, x2, y2, width, color, vertical);
+ break;
+ case STYLE_OUTSET:
+ paintOutsetLine(g, x1, y1, x2, y2, width, color, vertical);
+ break;
+ case STYLE_INSET:
+ paintInsetLine(g, x1, y1, x2, y2, width, color, vertical);
+ break;
+ case STYLE_NONE:
+ case STYLE_HIDDEN:
+ default:
+ // Nothing to do in these cases.
+ }
+ }
+
+ private void paintDottedLine(Graphics g, int x1, int y1, int x2, int y2,
+ int width, Color color, boolean vertical)
+ {
+ // FIXME: Implement this.
+ paintSolidLine(g, x1, y1, x2, y2, width, color, vertical);
+ }
+
+ private void paintDashedLine(Graphics g, int x1, int y1, int x2, int y2,
+ int width, Color color, boolean vertical)
+ {
+ // FIXME: Implement this.
+ paintSolidLine(g, x1, y1, x2, y2, width, color, vertical);
+ }
+
+ private void paintSolidLine(Graphics g, int x1, int y1, int x2, int y2,
+ int width, Color color, boolean vertical)
+ {
+ int x = Math.min(x1, x2);
+ int y = Math.min(y1, y1);
+ int w = Math.abs(x2 - x1);
+ int h = Math.abs(y2 - y1);
+ if (vertical)
+ {
+ w = width;
+ x -= width / 2;
+ }
+ else
+ {
+ h = width;
+ y -= width / 2;
+ }
+ g.setColor(color);
+ g.fillRect(x, y, w, h);
+ }
+
+ private void paintDoubleLine(Graphics g, int x1, int y1, int x2, int y2,
+ int width, Color color, boolean vertical)
+ {
+ // FIXME: Implement this.
+ paintSolidLine(g, x1, y1, x2, y2, width, color, vertical);
+ }
+
+ private void paintGrooveLine(Graphics g, int x1, int y1, int x2, int y2,
+ int width, Color color, boolean vertical)
+ {
+ // FIXME: Implement this.
+ paintSolidLine(g, x1, y1, x2, y2, width, color, vertical);
+ }
+
+ private void paintRidgeLine(Graphics g, int x1, int y1, int x2, int y2,
+ int width, Color color, boolean vertical)
+ {
+ // FIXME: Implement this.
+ paintSolidLine(g, x1, y1, x2, y2, width, color, vertical);
+ }
+
+ private void paintOutsetLine(Graphics g, int x1, int y1, int x2, int y2,
+ int width, Color color, boolean vertical)
+ {
+ // FIXME: Implement this.
+ paintSolidLine(g, x1, y1, x2, y2, width, color, vertical);
+ }
+
+ private void paintInsetLine(Graphics g, int x1, int y1, int x2, int y2,
+ int width, Color color, boolean vertical)
+ {
+ // FIXME: Implement this.
+ paintSolidLine(g, x1, y1, x2, y2, width, color, vertical);
+ }
+
+}
diff --git a/libjava/classpath/javax/swing/text/html/CSSParser.java b/libjava/classpath/javax/swing/text/html/CSSParser.java
new file mode 100644
index 000000000..5024c7b59
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/CSSParser.java
@@ -0,0 +1,561 @@
+/* CSSParser.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import java.io.*;
+
+/**
+ * Parses a CSS document. This works by way of a delegate that implements the
+ * CSSParserCallback interface. The delegate is notified of the following
+ * events:
+ * - Import statement: handleImport
+ * - Selectors handleSelector. This is invoked for each string. For example if
+ * the Reader contained p, bar , a {}, the delegate would be notified 4 times,
+ * for 'p,' 'bar' ',' and 'a'.
+ * - When a rule starts, startRule
+ * - Properties in the rule via the handleProperty. This
+ * is invoked one per property/value key, eg font size: foo;, would cause the
+ * delegate to be notified once with a value of 'font size'.
+ * - Values in the rule via the handleValue, this is notified for the total value.
+ * - When a rule ends, endRule
+ *
+ * @author Lillian Angel (langel@redhat.com)
+ */
+class CSSParser
+{
+
+ /**
+ * Receives all information about the CSS document structure while parsing it.
+ * The methods are invoked by parser.
+ */
+ static interface CSSParserCallback
+ {
+ /**
+ * Handles the import statment in the document.
+ *
+ * @param imp - the import string
+ */
+ public abstract void handleImport(String imp);
+
+ /**
+ * Called when the start of a rule is encountered.
+ */
+ public abstract void startRule();
+
+ /**
+ * Called when the end of a rule is encountered.
+ */
+ public abstract void endRule();
+
+ /**
+ * Handles the selector of a rule.
+ *
+ * @param selector - the selector in the rule
+ */
+ public abstract void handleSelector(String selector);
+
+ /**
+ * Handles the properties in the document.
+ *
+ * @param property - the property in the document.
+ */
+ public abstract void handleProperty(String property);
+
+ /**
+ * Handles the values in the document.
+ *
+ * @param value - the value to handle.
+ */
+ public abstract void handleValue(String value);
+
+ }
+
+ /**
+ * The identifier of the rule.
+ */
+ private static final int IDENTIFIER = 1;
+
+ /**
+ * The open bracket.
+ */
+ private static final int BRACKET_OPEN = 2;
+
+ /**
+ * The close bracket.
+ */
+ private static final int BRACKET_CLOSE = 3;
+
+ /**
+ * The open brace.
+ */
+ private static final int BRACE_OPEN = 4;
+
+ /**
+ * The close brace.
+ */
+ private static final int BRACE_CLOSE = 5;
+
+ /**
+ * The open parentheses.
+ */
+ private static final int PAREN_OPEN = 6;
+
+ /**
+ * The close parentheses.
+ */
+ private static final int PAREN_CLOSE = 7;
+
+ /**
+ * The end of the document.
+ */
+ private static final int END = -1;
+
+ /**
+ * The character mapping in the document.
+ */
+ // FIXME: What is this used for?
+ private static final char[] charMapping = null;
+
+ /**
+ * Set to true if one character has been read ahead.
+ */
+ private boolean didPushChar;
+
+ /**
+ * The read ahead character.
+ */
+ private int pushedChar;
+
+ /**
+ * Used to indicate blocks.
+ */
+ private int[] unitStack;
+
+ /**
+ * Number of valid blocks.
+ */
+ private int stackCount;
+
+ /**
+ * Holds the incoming CSS rules.
+ */
+ private Reader reader;
+
+ /**
+ * Set to true when the first non @ rule is encountered.
+ */
+ private boolean encounteredRuleSet;
+
+ /**
+ * The call back used to parse.
+ */
+ private CSSParser.CSSParserCallback callback;
+
+ /**
+ * nextToken() inserts the string here.
+ */
+ private char[] tokenBuffer;
+
+ /**
+ * Current number of chars in tokenBufferLength.
+ */
+ private int tokenBufferLength;
+
+ /**
+ * Set to true if any whitespace is read.
+ */
+ private boolean readWS;
+
+ /**
+ * Constructor
+ */
+ CSSParser()
+ {
+ tokenBuffer = new char[10];
+ }
+
+ /**
+ * Appends a character to the token buffer.
+ *
+ * @param c - the character to append
+ */
+ private void append(char c)
+ {
+ if (tokenBuffer.length >= tokenBufferLength)
+ {
+ char[] temp = new char[tokenBufferLength * 2];
+ if (tokenBuffer != null)
+ System.arraycopy(tokenBuffer, 0, temp, 0, tokenBufferLength);
+
+ temp[tokenBufferLength] = c;
+ tokenBuffer = temp;
+ }
+ else
+ tokenBuffer[tokenBufferLength] = c;
+ tokenBufferLength++;
+ }
+
+ /**
+ * Fetches the next token.
+ *
+ * @param c - the character to fetch.
+ * @return the location
+ * @throws IOException - any i/o error encountered while reading
+ */
+ private int nextToken(char c) throws IOException
+ {
+ readWS = false;
+ int next = readWS();
+
+ switch (next)
+ {
+ case '\"':
+ if (tokenBufferLength > 0)
+ tokenBufferLength--;
+ return IDENTIFIER;
+ case '\'':
+ if (tokenBufferLength > 0)
+ tokenBufferLength--;
+ return IDENTIFIER;
+ case '(':
+ return PAREN_OPEN;
+ case ')':
+ return PAREN_CLOSE;
+ case '{':
+ return BRACE_OPEN;
+ case '}':
+ return BRACE_CLOSE;
+ case '[':
+ return BRACKET_OPEN;
+ case ']':
+ return BRACKET_CLOSE;
+ case -1:
+ return END;
+ default:
+ pushChar(next);
+ getIdentifier(c);
+ return IDENTIFIER;
+ }
+ }
+
+ /**
+ * Reads a character from the stream.
+ *
+ * @return the number of characters read or -1 if end of stream is reached.
+ * @throws IOException - any i/o encountered while reading
+ */
+ private int readChar() throws IOException
+ {
+ if (didPushChar)
+ {
+ didPushChar = false;
+ return pushedChar;
+ }
+ return reader.read();
+ }
+
+ /**
+ * Parses the the contents of the reader using the
+ * callback.
+ *
+ * @param reader - the reader to read from
+ * @param callback - the callback instance
+ * @param parsingDeclaration - true if parsing a declaration
+ * @throws IOException - any i/o error from the reader
+ */
+ void parse(Reader reader, CSSParser.CSSParserCallback callback,
+ boolean parsingDeclaration)
+ throws IOException
+ {
+ this.reader = reader;
+ this.callback = callback;
+
+ try
+ {
+ if (!parsingDeclaration)
+ while(getNextStatement())
+ ;
+ else
+ parseDeclarationBlock();
+ }
+ catch (IOException ioe)
+ {
+ // Nothing to do here.
+ }
+ }
+
+ /**
+ * Skips any white space, returning the character after the white space.
+ *
+ * @return the character after the whitespace
+ * @throws IOException - any i/o error from the reader
+ */
+ private int readWS() throws IOException
+ {
+ int next = readChar();
+ while (Character.isWhitespace((char) next))
+ {
+ readWS = true;
+ int tempNext = readChar();
+ if (tempNext == END)
+ return next;
+ next = tempNext;
+ }
+
+ // Its all whitespace
+ return END;
+ }
+
+ /**
+ * Gets the next statement, returning false if the end is reached.
+ * A statement is either an At-rule, or a ruleset.
+ *
+ * @return false if the end is reached
+ * @throws IOException - any i/o error from the reader
+ */
+ private boolean getNextStatement() throws IOException
+ {
+ int c = nextToken((char) 0);
+ switch (c)
+ {
+ case PAREN_OPEN:
+ case BRACE_OPEN:
+ case BRACKET_OPEN:
+ parseTillClosed(c);
+ break;
+ case BRACKET_CLOSE:
+ case BRACE_CLOSE:
+ case PAREN_CLOSE:
+ throw new IOException("Not a proper statement.");
+ case IDENTIFIER:
+ if (tokenBuffer[0] == ('@'))
+ parseAtRule();
+ else
+ parseRuleSet();
+ break;
+ case END:
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Parses an @ rule, stopping at a matching brace pair, or ;.
+ *
+ * @throws IOException - any i/o error from the reader
+ */
+ private void parseAtRule() throws IOException
+ {
+ // An At-Rule begins with the "@" character followed immediately by a keyword.
+ // Following the keyword separated by a space is an At-rule statement appropriate
+ // to the At-keyword used. If the At-Rule is a simple declarative statement
+ // (charset, import, fontdef), it is terminated by a semi-colon (";".)
+ // If the At-Rule is a conditional or informative statement (media, page, font-face),
+ // it is followed by optional arguments and then a style declaration block inside matching
+ // curly braces ("{", "}".) At-Rules are sometimes nestable, depending on the context.
+ // If any part of an At-Rule is not understood, it should be ignored.
+
+ // FIXME: Not Implemented
+ // call handleimport
+ }
+
+ /**
+ * Parses the next rule set, which is a selector followed by a declaration
+ * block.
+ *
+ * @throws IOException - any i/o error from the reader
+ */
+ private void parseRuleSet() throws IOException
+ {
+ // call parseDeclarationBlock
+ // call parse selectors
+ // call parse identifiers
+ // call startrule/endrule
+ // FIXME: Not Implemented
+ }
+
+ /**
+ * Parses a set of selectors, returning false if the end of the stream is
+ * reached.
+ *
+ * @return false if the end of stream is reached
+ * @throws IOException - any i/o error from the reader
+ */
+ private boolean parseSelectors() throws IOException
+ {
+ // FIXME: Not Implemented
+ // call handleselector
+ return false;
+ }
+
+ /**
+ * Parses a declaration block. Which a number of declarations followed by a
+ * })].
+ *
+ * @throws IOException - any i/o error from the reader
+ */
+ private void parseDeclarationBlock() throws IOException
+ {
+ // call parseDeclaration
+ // FIXME: Not Implemented
+ }
+
+ /**
+ * Parses a single declaration, which is an identifier a : and another identifier.
+ * This returns the last token seen.
+ *
+ * @returns the last token
+ * @throws IOException - any i/o error from the reader
+ */
+ private int parseDeclaration() throws IOException
+ {
+ // call handleValue
+ // FIXME: Not Implemented
+ return 0;
+ }
+
+ /**
+ * Parses identifiers until c is encountered, returning the ending token,
+ * which will be IDENTIFIER if c is found.
+ *
+ * @param c - the stop character
+ * @param wantsBlocks - true if blocks are wanted
+ * @return the ending token
+ * @throws IOException - any i/o error from the reader
+ */
+ private int parseIdentifiers(char c, boolean wantsBlocks) throws IOException
+ {
+ // FIXME: Not implemented
+ // call handleproperty?
+ return 0;
+ }
+
+ /**
+ * Parses till a matching block close is encountered. This is only appropriate
+ * to be called at the top level (no nesting).
+ *
+ * @param i - FIXME
+ * @throws IOException - any i/o error from the reader
+ */
+ private void parseTillClosed(int i) throws IOException
+ {
+ // FIXME: Not Implemented
+ }
+
+ /**
+ * Gets an identifier, returning true if the length of the string is greater
+ * than 0, stopping when c, whitespace, or one of {}()[] is hit.
+ *
+ * @param c - the stop character
+ * @return returns true if the length of the string > 0
+ * @throws IOException - any i/o error from the reader
+ */
+ private boolean getIdentifier(char c) throws IOException
+ {
+ // FIXME: Not Implemented
+ return false;
+ }
+
+ /**
+ * Reads till c is encountered, escaping characters as necessary.
+ *
+ * @param c - the stop character
+ * @throws IOException - any i/o error from the reader
+ */
+ private void readTill(char c) throws IOException
+ {
+ // FIXME: Not Implemented
+ }
+
+ /**
+ * Parses a comment block.
+ *
+ * @throws IOException - any i/o error from the reader
+ */
+ private void readComment() throws IOException
+ {
+ // Should ignore comments. Read until end of comment.
+ // FIXME: Not implemented
+ }
+
+ /**
+ * Called when a block start is encountered ({[.
+ *
+ * @param start of block
+ */
+ private void startBlock(int start)
+ {
+ // FIXME: Not Implemented
+ }
+
+ /**
+ * Called when an end block is encountered )]}
+ *
+ * @param end of block
+ */
+ private void endBlock(int end)
+ {
+ // FIXME: Not Implemented
+ }
+
+ /**
+ * Checks if currently in a block.
+ *
+ * @return true if currently in a block.
+ */
+ private boolean inBlock()
+ {
+ // FIXME: Not Implemented
+ return false;
+ }
+
+ /**
+ * Supports one character look ahead, this will throw if called twice in a row.
+ *
+ * @param c - the character to push.
+ * @throws IOException - if called twice in a row
+ */
+ private void pushChar(int c) throws IOException
+ {
+ if (didPushChar)
+ throw new IOException("pushChar called twice.");
+ didPushChar = true;
+ pushedChar = c;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/FormSubmitEvent.java b/libjava/classpath/javax/swing/text/html/FormSubmitEvent.java
new file mode 100644
index 000000000..bc7c36f4b
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/FormSubmitEvent.java
@@ -0,0 +1,123 @@
+/* FormSubmitEvent.java -- Event fired on form submit
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import java.net.URL;
+
+import javax.swing.text.Element;
+
+/**
+ * The event fired on form submit.
+ *
+ * @since 1.5
+ */
+public class FormSubmitEvent
+ extends HTMLFrameHyperlinkEvent
+{
+
+ // FIXME: Use enums when available.
+ /**
+ * The submit method.
+ */
+ public static class MethodType
+ {
+ /**
+ * Indicates a form submit with HTTP method POST.
+ */
+ public static final MethodType POST = new MethodType();
+
+ /**
+ * Indicates a form submit with HTTP method GET.
+ */
+ public static final MethodType GET = new MethodType();
+
+ private MethodType()
+ {
+ }
+ }
+
+ /**
+ * The submit method.
+ */
+ private MethodType method;
+
+ /**
+ * The actual submit data.
+ */
+ private String data;
+
+ /**
+ * Creates a new FormSubmitEvent.
+ *
+ * @param source the source
+ * @param type the type of hyperlink update
+ * @param url the action url
+ * @param el the associated element
+ * @param target the target attribute
+ * @param m the submit method
+ * @param d the submit data
+ */
+ FormSubmitEvent(Object source, EventType type, URL url, Element el,
+ String target, MethodType m, String d)
+ {
+ super(source, type, url, el, target);
+ method = m;
+ data = d;
+ }
+
+ /**
+ * Returns the submit data.
+ *
+ * @return the submit data
+ */
+ public String getData()
+ {
+ return data;
+ }
+
+ /**
+ * Returns the HTTP submit method.
+ *
+ * @return the HTTP submit method
+ */
+ public MethodType getMethod()
+ {
+ return method;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/FormView.java b/libjava/classpath/javax/swing/text/html/FormView.java
new file mode 100644
index 000000000..61c568f02
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/FormView.java
@@ -0,0 +1,870 @@
+/* FormView.java -- A view for a variety of HTML form elements
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import java.awt.Component;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLEncoder;
+
+import javax.swing.ButtonModel;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JEditorPane;
+import javax.swing.JList;
+import javax.swing.JPasswordField;
+import javax.swing.JRadioButton;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.ComponentView;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.ElementIterator;
+import javax.swing.text.StyleConstants;
+
+/**
+ * A View that renders HTML form elements like buttons and input fields.
+ * This is implemented as a {@link ComponentView} that creates different Swing
+ * component depending on the type and setting of the different form elements.
+ *
+ * Namely, this view creates the following components:
+ * <table>
+ * <tr><th>Element type</th><th>Swing component</th></tr>
+ * <tr><td>input, button</td><td>JButton</td></tr>
+ * <tr><td>input, checkbox</td><td>JButton</td></tr>
+ * <tr><td>input, image</td><td>JButton</td></tr>
+ * <tr><td>input, password</td><td>JButton</td></tr>
+ * <tr><td>input, radio</td><td>JButton</td></tr>
+ * <tr><td>input, reset</td><td>JButton</td></tr>
+ * <tr><td>input, submit</td><td>JButton</td></tr>
+ * <tr><td>input, text</td><td>JButton</td></tr>
+ * <tr><td>select, size > 1 or with multiple attribute</td>
+ * <td>JList in JScrollPane</td></tr>
+ * <tr><td>select, size unspecified or == 1</td><td>JComboBox</td></tr>
+ * <tr><td>textarea, text</td><td>JTextArea in JScrollPane</td></tr>
+ * <tr><td>input, file</td><td>JTextField</td></tr>
+ * </table>
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class FormView
+ extends ComponentView
+ implements ActionListener
+{
+
+ protected class MouseEventListener
+ extends MouseAdapter
+ {
+ /**
+ * Creates a new <code>MouseEventListener</code>.
+ */
+ protected MouseEventListener()
+ {
+ // Nothing to do here.
+ }
+
+ public void mouseReleased(MouseEvent ev)
+ {
+ String data = getImageData(ev.getPoint());
+ imageSubmit(data);
+ }
+ }
+
+ /**
+ * Actually submits the form data.
+ */
+ private class SubmitThread
+ extends Thread
+ {
+ /**
+ * The submit data.
+ */
+ private String data;
+
+ /**
+ * Creates a new SubmitThread.
+ *
+ * @param d the submit data
+ */
+ SubmitThread(String d)
+ {
+ data = d;
+ }
+
+ /**
+ * Actually performs the submit.
+ */
+ public void run()
+ {
+ if (data.length() > 0)
+ {
+ final String method = getMethod();
+ final URL actionURL = getActionURL();
+ final String target = getTarget();
+ URLConnection conn;
+ final JEditorPane editor = (JEditorPane) getContainer();
+ final HTMLDocument doc = (HTMLDocument) editor.getDocument();
+ HTMLEditorKit kit = (HTMLEditorKit) editor.getEditorKit();
+ if (kit.isAutoFormSubmission())
+ {
+ try
+ {
+ final URL url;
+ if (method != null && method.equals("post"))
+ {
+ // Perform POST.
+ url = actionURL;
+ conn = url.openConnection();
+ postData(conn, data);
+ }
+ else
+ {
+ // Default to GET.
+ url = new URL(actionURL + "?" + data);
+ }
+ Runnable loadDoc = new Runnable()
+ {
+ public void run()
+ {
+ if (doc.isFrameDocument())
+ {
+ editor.fireHyperlinkUpdate(createSubmitEvent(method,
+ actionURL,
+ target));
+ }
+ else
+ {
+ try
+ {
+ editor.setPage(url);
+ }
+ catch (IOException ex)
+ {
+ // Oh well.
+ ex.printStackTrace();
+ }
+ }
+ }
+ };
+ SwingUtilities.invokeLater(loadDoc);
+ }
+ catch (MalformedURLException ex)
+ {
+ ex.printStackTrace();
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ else
+ {
+ editor.fireHyperlinkUpdate(createSubmitEvent(method,actionURL,
+ target));
+ }
+ }
+ }
+
+ /**
+ * Determines the submit method.
+ *
+ * @return the submit method
+ */
+ private String getMethod()
+ {
+ AttributeSet formAtts = getFormAttributes();
+ String method = null;
+ if (formAtts != null)
+ {
+ method = (String) formAtts.getAttribute(HTML.Attribute.METHOD);
+ }
+ return method;
+ }
+
+ /**
+ * Determines the action URL.
+ *
+ * @return the action URL
+ */
+ private URL getActionURL()
+ {
+ AttributeSet formAtts = getFormAttributes();
+ HTMLDocument doc = (HTMLDocument) getElement().getDocument();
+ URL url = doc.getBase();
+ if (formAtts != null)
+ {
+ String action =
+ (String) formAtts.getAttribute(HTML.Attribute.ACTION);
+ if (action != null)
+ {
+ try
+ {
+ url = new URL(url, action);
+ }
+ catch (MalformedURLException ex)
+ {
+ url = null;
+ }
+ }
+ }
+ return url;
+ }
+
+ /**
+ * Fetches the target attribute.
+ *
+ * @return the target attribute or _self if none is present
+ */
+ private String getTarget()
+ {
+ AttributeSet formAtts = getFormAttributes();
+ String target = null;
+ if (formAtts != null)
+ {
+ target = (String) formAtts.getAttribute(HTML.Attribute.TARGET);
+ if (target != null)
+ target = target.toLowerCase();
+ }
+ if (target == null)
+ target = "_self";
+ return target;
+ }
+
+ /**
+ * Posts the form data over the specified connection.
+ *
+ * @param conn the connection
+ */
+ private void postData(URLConnection conn, String data)
+ {
+ conn.setDoOutput(true);
+ PrintWriter out = null;
+ try
+ {
+ out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream()));
+ out.print(data);
+ out.flush();
+ }
+ catch (IOException ex)
+ {
+ // Deal with this!
+ ex.printStackTrace();
+ }
+ finally
+ {
+ if (out != null)
+ out.close();
+ }
+ }
+
+ /**
+ * Determines the attributes from the relevant form tag.
+ *
+ * @return the attributes from the relevant form tag, <code>null</code>
+ * when there is no form tag
+ */
+ private AttributeSet getFormAttributes()
+ {
+ AttributeSet atts = null;
+ Element form = getFormElement();
+ if (form != null)
+ atts = form.getAttributes();
+ return atts;
+ }
+
+ /**
+ * Creates the submit event that should be fired.
+ *
+ * This is package private to avoid accessor methods.
+ *
+ * @param method the submit method
+ * @param actionURL the action URL
+ * @param target the target
+ *
+ * @return the submit event
+ */
+ FormSubmitEvent createSubmitEvent(String method, URL actionURL,
+ String target)
+ {
+ FormSubmitEvent.MethodType m = "post".equals(method)
+ ? FormSubmitEvent.MethodType.POST
+ : FormSubmitEvent.MethodType.GET;
+ return new FormSubmitEvent(FormView.this,
+ HyperlinkEvent.EventType.ACTIVATED,
+ actionURL, getElement(), target, m, data);
+ }
+ }
+
+ /**
+ * If the value attribute of an <code>&lt;input type=&quot;submit&quot;&gt>
+ * tag is not specified, then this string is used.
+ *
+ * @deprecated As of JDK1.3 the value is fetched from the UIManager property
+ * <code>FormView.submitButtonText</code>.
+ */
+ public static final String SUBMIT =
+ UIManager.getString("FormView.submitButtonText");
+
+ /**
+ * If the value attribute of an <code>&lt;input type=&quot;reset&quot;&gt>
+ * tag is not specified, then this string is used.
+ *
+ * @deprecated As of JDK1.3 the value is fetched from the UIManager property
+ * <code>FormView.resetButtonText</code>.
+ */
+ public static final String RESET =
+ UIManager.getString("FormView.resetButtonText");
+
+ /**
+ * If this is true, the maximum size is set to the preferred size.
+ */
+ private boolean maxIsPreferred;
+
+ /**
+ * Creates a new <code>FormView</code>.
+ *
+ * @param el the element that is displayed by this view.
+ */
+ public FormView(Element el)
+ {
+ super(el);
+ }
+
+ /**
+ * Creates the correct AWT component for rendering the form element.
+ */
+ protected Component createComponent()
+ {
+ Component comp = null;
+ Element el = getElement();
+ AttributeSet atts = el.getAttributes();
+ Object tag = atts.getAttribute(StyleConstants.NameAttribute);
+ Object model = atts.getAttribute(StyleConstants.ModelAttribute);
+ if (tag.equals(HTML.Tag.INPUT))
+ {
+ String type = (String) atts.getAttribute(HTML.Attribute.TYPE);
+ if (type.equals("button"))
+ {
+ String value = (String) atts.getAttribute(HTML.Attribute.VALUE);
+ JButton b = new JButton(value);
+ if (model != null)
+ {
+ b.setModel((ButtonModel) model);
+ b.addActionListener(this);
+ }
+ comp = b;
+ maxIsPreferred = true;
+ }
+ else if (type.equals("checkbox"))
+ {
+ if (model instanceof ResetableToggleButtonModel)
+ {
+ ResetableToggleButtonModel m =
+ (ResetableToggleButtonModel) model;
+ JCheckBox c = new JCheckBox();
+ c.setModel(m);
+ comp = c;
+ maxIsPreferred = true;
+ }
+ }
+ else if (type.equals("image"))
+ {
+ String src = (String) atts.getAttribute(HTML.Attribute.SRC);
+ JButton b;
+ try
+ {
+ URL base = ((HTMLDocument) el.getDocument()).getBase();
+ URL srcURL = new URL(base, src);
+ ImageIcon icon = new ImageIcon(srcURL);
+ b = new JButton(icon);
+ }
+ catch (MalformedURLException ex)
+ {
+ b = new JButton(src);
+ }
+ if (model != null)
+ {
+ b.setModel((ButtonModel) model);
+ b.addActionListener(this);
+ }
+ comp = b;
+ maxIsPreferred = true;
+ }
+ else if (type.equals("password"))
+ {
+ int size = HTML.getIntegerAttributeValue(atts, HTML.Attribute.SIZE,
+ -1);
+ JTextField tf = new JPasswordField();
+ if (size > 0)
+ tf.setColumns(size);
+ else
+ tf.setColumns(20);
+ if (model != null)
+ tf.setDocument((Document) model);
+ tf.addActionListener(this);
+ comp = tf;
+ maxIsPreferred = true;
+ }
+ else if (type.equals("radio"))
+ {
+ if (model instanceof ResetableToggleButtonModel)
+ {
+ ResetableToggleButtonModel m =
+ (ResetableToggleButtonModel) model;
+ JRadioButton c = new JRadioButton();
+ c.setModel(m);
+ comp = c;
+ maxIsPreferred = true;
+ }
+ }
+ else if (type.equals("reset"))
+ {
+ String value = (String) atts.getAttribute(HTML.Attribute.VALUE);
+ if (value == null)
+ value = UIManager.getString("FormView.resetButtonText");
+ JButton b = new JButton(value);
+ if (model != null)
+ {
+ b.setModel((ButtonModel) model);
+ b.addActionListener(this);
+ }
+ comp = b;
+ maxIsPreferred = true;
+ }
+ else if (type.equals("submit"))
+ {
+ String value = (String) atts.getAttribute(HTML.Attribute.VALUE);
+ if (value == null)
+ value = UIManager.getString("FormView.submitButtonText");
+ JButton b = new JButton(value);
+ if (model != null)
+ {
+ b.setModel((ButtonModel) model);
+ b.addActionListener(this);
+ }
+ comp = b;
+ maxIsPreferred = true;
+ }
+ else if (type.equals("text"))
+ {
+ int size = HTML.getIntegerAttributeValue(atts, HTML.Attribute.SIZE,
+ -1);
+ JTextField tf = new JTextField();
+ if (size > 0)
+ tf.setColumns(size);
+ else
+ tf.setColumns(20);
+ if (model != null)
+ tf.setDocument((Document) model);
+ tf.addActionListener(this);
+ comp = tf;
+ maxIsPreferred = true;
+ }
+ }
+ else if (tag == HTML.Tag.TEXTAREA)
+ {
+ JTextArea textArea = new JTextArea((Document) model);
+ int rows = HTML.getIntegerAttributeValue(atts, HTML.Attribute.ROWS, 1);
+ textArea.setRows(rows);
+ int cols = HTML.getIntegerAttributeValue(atts, HTML.Attribute.COLS, 20);
+ textArea.setColumns(cols);
+ maxIsPreferred = true;
+ comp = new JScrollPane(textArea,
+ JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
+ JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
+ }
+ else if (tag == HTML.Tag.SELECT)
+ {
+ if (model instanceof SelectListModel)
+ {
+ SelectListModel slModel = (SelectListModel) model;
+ JList list = new JList(slModel);
+ int size = HTML.getIntegerAttributeValue(atts, HTML.Attribute.SIZE,
+ 1);
+ list.setVisibleRowCount(size);
+ list.setSelectionModel(slModel.getSelectionModel());
+ comp = new JScrollPane(list);
+ }
+ else if (model instanceof SelectComboBoxModel)
+ {
+ SelectComboBoxModel scbModel = (SelectComboBoxModel) model;
+ comp = new JComboBox(scbModel);
+ }
+ maxIsPreferred = true;
+ }
+ return comp;
+ }
+
+ /**
+ * Determines the maximum span for this view on the specified axis.
+ *
+ * @param axis the axis along which to determine the span
+ *
+ * @return the maximum span for this view on the specified axis
+ *
+ * @throws IllegalArgumentException if the axis is invalid
+ */
+ public float getMaximumSpan(int axis)
+ {
+ float span;
+ if (maxIsPreferred)
+ span = getPreferredSpan(axis);
+ else
+ span = super.getMaximumSpan(axis);
+ return span;
+ }
+
+ /**
+ * Processes an action from the Swing component.
+ *
+ * If the action comes from a submit button, the form is submitted by calling
+ * {@link #submitData}. In the case of a reset button, the form is reset to
+ * the original state. If the action comes from a password or text field,
+ * then the input focus is transferred to the next input element in the form,
+ * unless this text/password field is the last one, in which case the form
+ * is submitted.
+ *
+ * @param ev the action event
+ */
+ public void actionPerformed(ActionEvent ev)
+ {
+ Element el = getElement();
+ Object tag = el.getAttributes().getAttribute(StyleConstants.NameAttribute);
+ if (tag.equals(HTML.Tag.INPUT))
+ {
+ AttributeSet atts = el.getAttributes();
+ String type = (String) atts.getAttribute(HTML.Attribute.TYPE);
+ if (type.equals("submit"))
+ submitData(getFormData());
+ else if (type.equals("reset"))
+ resetForm();
+ }
+ // FIXME: Implement the remaining actions.
+ }
+
+ /**
+ * Submits the form data. A separate thread is created to do the
+ * transmission.
+ *
+ * @param data the form data
+ */
+ protected void submitData(String data)
+ {
+ SubmitThread submitThread = new SubmitThread(data);
+ submitThread.start();
+ }
+
+ /**
+ * Submits the form data in response to a click on a
+ * <code>&lt;input type=&quot;image&quot;&gt;</code> element.
+ *
+ * @param imageData the mouse click coordinates
+ */
+ protected void imageSubmit(String imageData)
+ {
+ // FIXME: Implement this.
+ }
+
+ /**
+ * Determines the image data that should be submitted in response to a
+ * mouse click on a image. This is either 'x=<p.x>&y=<p.y>' if the name
+ * attribute of the element is null or '' or
+ * <name>.x=<p.x>&<name>.y=<p.y>' when the name attribute is not empty.
+ *
+ * @param p the coordinates of the mouseclick
+ */
+ String getImageData(Point p)
+ {
+ String name = (String) getElement().getAttributes()
+ .getAttribute(HTML.Attribute.NAME);
+ String data;
+ if (name == null || name.equals(""))
+ {
+ data = "x=" + p.x + "&y=" + p.y;
+ }
+ else
+ {
+ data = name + ".x=" + p.x + "&" + name + ".y=" + p.y;
+ }
+ return data;
+ }
+
+ /**
+ * Determines and returns the enclosing form element if there is any.
+ *
+ * This is package private to avoid accessor methods.
+ *
+ * @return the enclosing form element, or <code>null</code> if there is no
+ * enclosing form element
+ */
+ Element getFormElement()
+ {
+ Element form = null;
+ Element el = getElement();
+ while (el != null && form == null)
+ {
+ AttributeSet atts = el.getAttributes();
+ if (atts.getAttribute(StyleConstants.NameAttribute) == HTML.Tag.FORM)
+ form = el;
+ else
+ el = el.getParentElement();
+ }
+ return form;
+ }
+
+ /**
+ * Determines the form data that is about to be submitted.
+ *
+ * @return the form data
+ */
+ private String getFormData()
+ {
+ Element form = getFormElement();
+ StringBuilder b = new StringBuilder();
+ if (form != null)
+ {
+ ElementIterator i = new ElementIterator(form);
+ Element next;
+ while ((next = i.next()) != null)
+ {
+ if (next.isLeaf())
+ {
+ AttributeSet atts = next.getAttributes();
+ String type = (String) atts.getAttribute(HTML.Attribute.TYPE);
+ if (type != null && type.equals("submit")
+ && next != getElement())
+ {
+ // Skip this. This is not the actual submit trigger.
+ }
+ else if (type == null || ! type.equals("image"))
+ {
+ getElementFormData(next, b);
+ }
+ }
+ }
+ }
+ return b.toString();
+ }
+
+ /**
+ * Fetches the form data from the specified element and appends it to
+ * the data string.
+ *
+ * @param el the element from which to fetch form data
+ * @param b the data string
+ */
+ private void getElementFormData(Element el, StringBuilder b)
+ {
+ AttributeSet atts = el.getAttributes();
+ String name = (String) atts.getAttribute(HTML.Attribute.NAME);
+ if (name != null)
+ {
+ String value = null;
+ HTML.Tag tag = (HTML.Tag) atts.getAttribute(StyleConstants.NameAttribute);
+ if (tag == HTML.Tag.SELECT)
+ {
+ getSelectData(atts, b);
+ }
+ else
+ {
+ if (tag == HTML.Tag.INPUT)
+ value = getInputFormData(atts);
+ else if (tag == HTML.Tag.TEXTAREA)
+ value = getTextAreaData(atts);
+ if (name != null && value != null)
+ {
+ addData(b, name, value);
+ }
+ }
+ }
+ }
+
+ /**
+ * Fetches form data from select boxes.
+ *
+ * @param atts the attributes of the element
+ *
+ * @param b the form data string to append to
+ */
+ private void getSelectData(AttributeSet atts, StringBuilder b)
+ {
+ String name = (String) atts.getAttribute(HTML.Attribute.NAME);
+ if (name != null)
+ {
+ Object m = atts.getAttribute(StyleConstants.ModelAttribute);
+ if (m instanceof SelectListModel)
+ {
+ SelectListModel sl = (SelectListModel) m;
+ ListSelectionModel lsm = sl.getSelectionModel();
+ for (int i = 0; i < sl.getSize(); i++)
+ {
+ if (lsm.isSelectedIndex(i))
+ {
+ Option o = (Option) sl.getElementAt(i);
+ addData(b, name, o.getValue());
+ }
+ }
+ }
+ else if (m instanceof SelectComboBoxModel)
+ {
+ SelectComboBoxModel scb = (SelectComboBoxModel) m;
+ Option o = (Option) scb.getSelectedItem();
+ if (o != null)
+ addData(b, name, o.getValue());
+ }
+ }
+ }
+
+ /**
+ * Fetches form data from a textarea.
+ *
+ * @param atts the attributes
+ *
+ * @return the form data
+ */
+ private String getTextAreaData(AttributeSet atts)
+ {
+ Document doc = (Document) atts.getAttribute(StyleConstants.ModelAttribute);
+ String data;
+ try
+ {
+ data = doc.getText(0, doc.getLength());
+ }
+ catch (BadLocationException ex)
+ {
+ data = null;
+ }
+ return data;
+ }
+
+ /**
+ * Fetches form data from an input tag.
+ *
+ * @param atts the attributes from which to fetch the data
+ *
+ * @return the field value
+ */
+ private String getInputFormData(AttributeSet atts)
+ {
+ String type = (String) atts.getAttribute(HTML.Attribute.TYPE);
+ Object model = atts.getAttribute(StyleConstants.ModelAttribute);
+ String value = null;
+ if (type.equals("text") || type.equals("password"))
+ {
+ Document doc = (Document) model;
+ try
+ {
+ value = doc.getText(0, doc.getLength());
+ }
+ catch (BadLocationException ex)
+ {
+ // Sigh.
+ assert false;
+ }
+ }
+ else if (type.equals("hidden") || type.equals("submit"))
+ {
+ value = (String) atts.getAttribute(HTML.Attribute.VALUE);
+ if (value == null)
+ value = "";
+ }
+ // TODO: Implement the others. radio, checkbox and file.
+ return value;
+ }
+
+ /**
+ * Actually adds the specified data to the string. It URL encodes
+ * the name and value and handles separation of the fields.
+ *
+ * @param b the string at which the form data to be added
+ * @param name the name of the field
+ * @param value the value
+ */
+ private void addData(StringBuilder b, String name, String value)
+ {
+ if (b.length() > 0)
+ b.append('&');
+ String encName = URLEncoder.encode(name);
+ b.append(encName);
+ b.append('=');
+ String encValue = URLEncoder.encode(value);
+ b.append(encValue);
+ }
+
+ /**
+ * Resets the form data to their initial state.
+ */
+ private void resetForm()
+ {
+ Element form = getFormElement();
+ if (form != null)
+ {
+ ElementIterator iter = new ElementIterator(form);
+ Element next;
+ while ((next = iter.next()) != null)
+ {
+ if (next.isLeaf())
+ {
+ AttributeSet atts = next.getAttributes();
+ Object m = atts.getAttribute(StyleConstants.ModelAttribute);
+ if (m instanceof ResetableModel)
+ ((ResetableModel) m).reset();
+ }
+ }
+ }
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/FrameSetView.java b/libjava/classpath/javax/swing/text/html/FrameSetView.java
new file mode 100644
index 000000000..e3252d79c
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/FrameSetView.java
@@ -0,0 +1,274 @@
+/* FrameSetView.java -- Implements HTML frameset
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import java.util.StringTokenizer;
+
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BoxView;
+import javax.swing.text.Element;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+
+/**
+ * Implements HTML framesets. This is implemented as a vertical box that
+ * holds the rows of the frameset. Each row is again a horizontal box that
+ * holds the actual columns.
+ */
+public class FrameSetView
+ extends BoxView
+{
+
+ /**
+ * A row of a frameset.
+ */
+ private class FrameSetRow
+ extends BoxView
+ {
+ private int row;
+ FrameSetRow(Element el, int r)
+ {
+ super(el, X_AXIS);
+ row = r;
+ }
+
+ protected void loadChildren(ViewFactory f)
+ {
+ // Load the columns here.
+ Element el = getElement();
+ View[] columns = new View[numViews[X_AXIS]];
+ int offset = row * numViews[X_AXIS];
+ for (int c = 0; c < numViews[X_AXIS]; c++)
+ {
+ Element child = el.getElement(offset + c);
+ columns[c] = f.create(child);
+ }
+ replace(0, 0, columns);
+ }
+
+ protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
+ int[] spans)
+ {
+ int numRows = numViews[X_AXIS];
+ int[] abs = absolute[X_AXIS];
+ int[] rel = relative[X_AXIS];
+ int[] perc = percent[X_AXIS];
+ layoutViews(targetSpan, axis, offsets, spans, numRows, abs, rel, perc);
+ }
+ }
+
+ /**
+ * Holds the absolute layout information for the views along one axis. The
+ * indices are absolute[axis][index], where axis is either X_AXIS (columns)
+ * or Y_AXIS (rows). Rows or columns that don't have absolute layout have
+ * a -1 in this array.
+ */
+ int[][] absolute;
+
+ /**
+ * Holds the relative (*) layout information for the views along one axis.
+ * The indices are relative[axis][index], where axis is either X_AXIS
+ * (columns) or Y_AXIS (rows). Rows or columns that don't have relative
+ * layout have a Float.NaN in this array.
+ */
+ int[][] relative;
+
+ /**
+ * Holds the relative (%) layout information for the views along one axis.
+ * The indices are relative[axis][index], where axis is either X_AXIS
+ * (columns) or Y_AXIS (rows). Rows or columns that don't have relative
+ * layout have a Float.NaN in this array.
+ *
+ * The percentage is divided by 100 so that we hold the actual fraction here.
+ */
+ int[][] percent;
+
+ /**
+ * The number of children in each direction.
+ */
+ int[] numViews;
+
+ FrameSetView(Element el)
+ {
+ super(el, Y_AXIS);
+ numViews = new int[2];
+ absolute = new int[2][];
+ relative = new int[2][];
+ percent = new int[2][];
+ }
+
+ /**
+ * Loads the children and places them inside the grid.
+ */
+ protected void loadChildren(ViewFactory f)
+ {
+ parseRowsCols();
+ // Set up the rows.
+ View[] rows = new View[numViews[Y_AXIS]];
+ for (int r = 0; r < numViews[Y_AXIS]; r++)
+ {
+ rows[r] = new FrameSetRow(getElement(), r);
+ }
+ replace(0, 0, rows);
+ }
+
+ /**
+ * Parses the rows and cols attributes and sets up the layout info.
+ */
+ private void parseRowsCols()
+ {
+ Element el = getElement();
+ AttributeSet atts = el.getAttributes();
+ String cols = (String) atts.getAttribute(HTML.Attribute.COLS);
+ if (cols == null) // Defaults to '100%' when not specified.
+ cols = "100%";
+ parseLayout(cols, X_AXIS);
+ String rows = (String) atts.getAttribute(HTML.Attribute.ROWS);
+ if (rows == null) // Defaults to '100%' when not specified.
+ rows = "100%";
+ parseLayout(rows, Y_AXIS);
+ }
+
+ /**
+ * Parses the cols or rows attribute and places the layout info in the
+ * appropriate arrays.
+ *
+ * @param att the attributes to parse
+ * @param axis the axis
+ */
+ private void parseLayout(String att, int axis)
+ {
+ StringTokenizer tokens = new StringTokenizer(att, ",");
+ numViews[axis] = tokens.countTokens();
+ absolute[axis] = new int[numViews[axis]];
+ relative[axis] = new int[numViews[axis]];
+ percent[axis] = new int[numViews[axis]];
+ for (int index = 0; tokens.hasMoreTokens(); index++)
+ {
+ String token = tokens.nextToken();
+ int p = token.indexOf('%');
+ int s = token.indexOf('*');
+ if (p != -1)
+ {
+ // Percent value.
+ String number = token.substring(0, p);
+ try
+ {
+ percent[axis][index] = Integer.parseInt(number);
+ }
+ catch (NumberFormatException ex)
+ {
+ // Leave value as 0 then.
+ }
+ }
+ else if (s != -1)
+ {
+ // Star relative value.
+ String number = token.substring(0, s);
+ try
+ {
+ relative[axis][index] = Integer.parseInt(number);
+ }
+ catch (NumberFormatException ex)
+ {
+ // Leave value as 0 then.
+ }
+ }
+ else
+ {
+ // Absolute value.
+ try
+ {
+ absolute[axis][index] = Integer.parseInt(token);
+ }
+ catch (NumberFormatException ex)
+ {
+ // Leave value as 0 then.
+ }
+ }
+ }
+ }
+
+ protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
+ int[] spans)
+ {
+ int numRows = numViews[Y_AXIS];
+ int[] abs = absolute[Y_AXIS];
+ int[] rel = relative[Y_AXIS];
+ int[] perc = percent[Y_AXIS];
+ layoutViews(targetSpan, axis, offsets, spans, numRows, abs, rel, perc);
+ }
+
+ void layoutViews(int targetSpan, int axis, int[] offsets, int[] spans,
+ int numViews, int[] abs, int[] rel, int[] perc)
+ {
+ // We need two passes. In the first pass we layout the absolute and
+ // percent values and accumulate the needed space. In the second pass
+ // the relative values are distributed and the offsets are set.
+ int total = 0;
+ int relTotal = 0;
+ for (int i = 0; i < numViews; i++)
+ {
+ if (abs[i] > 0)
+ {
+ spans[i] = abs[i];
+ total += spans[i];
+ }
+ else if (perc[i] > 0)
+ {
+ spans[i] = (targetSpan * perc[i]) / 100;
+ total += spans[i];
+ }
+ else if (rel[i] > 0)
+ {
+ relTotal += rel[i];
+ }
+ }
+ int offs = 0;
+ for (int i = 0; i < numViews; i++)
+ {
+ if (relTotal > 0 && rel[i] > 0)
+ {
+ spans[i] = targetSpan * (rel[i] / relTotal);
+ }
+ offsets[i] = offs;
+ offs += spans[i];
+ }
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/FrameView.java b/libjava/classpath/javax/swing/text/html/FrameView.java
new file mode 100644
index 000000000..cd4e44a98
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/FrameView.java
@@ -0,0 +1,233 @@
+/* FrameView.java -- Renders HTML frame tags
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import java.awt.Component;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.swing.JEditorPane;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.ComponentView;
+import javax.swing.text.Element;
+import javax.swing.text.View;
+
+/**
+ * A view that is responsible for rendering HTML frame tags.
+ * This is accomplished by a specialized {@link ComponentView}
+ * that embeds a JEditorPane with an own document.
+ */
+class FrameView
+ extends ComponentView
+ implements HyperlinkListener
+{
+
+ /**
+ * Creates a new FrameView for the specified element.
+ *
+ * @param el the element for the view
+ */
+ FrameView(Element el)
+ {
+ super(el);
+ }
+
+ /**
+ * Creates the element that will be embedded in the view.
+ * This will be a JEditorPane with the appropriate content set.
+ *
+ * @return the element that will be embedded in the view
+ */
+ protected Component createComponent()
+ {
+ Element el = getElement();
+ AttributeSet atts = el.getAttributes();
+ JEditorPane html = new JEditorPane();
+ html.addHyperlinkListener(this);
+ URL base = ((HTMLDocument) el.getDocument()).getBase();
+ String srcAtt = (String) atts.getAttribute(HTML.Attribute.SRC);
+ if (srcAtt != null && ! srcAtt.equals(""))
+ {
+ try
+ {
+ URL page = new URL(base, srcAtt);
+ html.setPage(page);
+ ((HTMLDocument) html.getDocument()).setFrameDocument(true);
+ }
+ catch (MalformedURLException ex)
+ {
+ // Leave page empty.
+ }
+ catch (IOException ex)
+ {
+ // Leave page empty.
+ }
+ }
+ return html;
+ }
+
+ /**
+ * Catches hyperlink events on that frame's editor and forwards it to
+ * the outermost editorpane.
+ */
+ public void hyperlinkUpdate(HyperlinkEvent event)
+ {
+ JEditorPane outer = getTopEditorPane();
+ if (outer != null)
+ {
+ if (event instanceof HTMLFrameHyperlinkEvent)
+ {
+ HTMLFrameHyperlinkEvent hfhe = (HTMLFrameHyperlinkEvent) event;
+ if (hfhe.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
+ {
+ String target = hfhe.getTarget();
+ if (event instanceof FormSubmitEvent)
+ {
+ handleFormSubmitEvent(hfhe, outer, target);
+ }
+ else // No FormSubmitEvent.
+ {
+ handleHyperlinkEvent(hfhe, outer, target);
+ }
+ }
+ }
+ else
+ {
+ // Simply forward this event.
+ outer.fireHyperlinkUpdate(event);
+ }
+ }
+ }
+
+ /**
+ * Handles normal hyperlink events.
+ *
+ * @param event the event
+ * @param outer the top editor
+ * @param target the target
+ */
+ private void handleHyperlinkEvent(HyperlinkEvent event,
+ JEditorPane outer, String target)
+ {
+ if (target.equals("_top"))
+ {
+ try
+ {
+ outer.setPage(event.getURL());
+ }
+ catch (IOException ex)
+ {
+ // Well...
+ ex.printStackTrace();
+ }
+ }
+ if (! outer.isEditable())
+ {
+ outer.fireHyperlinkUpdate
+ (new HTMLFrameHyperlinkEvent(outer,
+ event.getEventType(),
+ event.getURL(),
+ event.getDescription(),
+ getElement(),
+ target));
+ }
+ }
+
+ /**
+ * Handles form submit events.
+ *
+ * @param event the event
+ * @param outer the top editor
+ * @param target the target
+ */
+ private void handleFormSubmitEvent(HTMLFrameHyperlinkEvent event,
+ JEditorPane outer,
+ String target)
+ {
+ HTMLEditorKit kit = (HTMLEditorKit) outer.getEditorKit();
+ if (kit != null && kit.isAutoFormSubmission())
+ {
+ if (target.equals("_top"))
+ {
+ try
+ {
+ outer.setPage(event.getURL());
+ }
+ catch (IOException ex)
+ {
+ // Well...
+ ex.printStackTrace();
+ }
+ }
+ else
+ {
+ HTMLDocument doc =
+ (HTMLDocument) outer.getDocument();
+ doc.processHTMLFrameHyperlinkEvent(event);
+ }
+ }
+ else
+ {
+ outer.fireHyperlinkUpdate(event);
+ }
+ }
+
+ /**
+ * Determines the topmost editor in a nested frameset.
+ *
+ * @return the topmost editor in a nested frameset
+ */
+ private JEditorPane getTopEditorPane()
+ {
+ View parent = getParent();
+ View top = null;
+ while (parent != null)
+ {
+ if (parent instanceof FrameSetView)
+ top = parent;
+ }
+ JEditorPane editor = null;
+ if (top != null)
+ editor = (JEditorPane) top.getContainer();
+ return editor;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/HRuleView.java b/libjava/classpath/javax/swing/text/html/HRuleView.java
new file mode 100644
index 000000000..9be1efff3
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/HRuleView.java
@@ -0,0 +1,189 @@
+/* HRuleView.java -- Horizontal dash in HTML documents.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+import javax.swing.text.Element;
+import javax.swing.text.View;
+
+/**
+ * Represents the long horizontal separating dash that can be inserted into the
+ * HTML documents with HR tag.
+ */
+class HRuleView extends InlineView
+{
+ /**
+ * The null view, indicating, that nothing should be painted ahead the
+ * breaking point.
+ */
+ View nullView;
+
+ /**
+ * The height of the horizontal dash area.
+ */
+ static int HEIGHT = 4;
+
+ /**
+ * The imaginary invisible view that stays after end of line after the
+ * breaking procedure. It occupies on character.
+ */
+ class Beginning extends NullView
+ {
+ /**
+ * The break offset that becomes the views start offset.
+ */
+ int breakOffset;
+
+ /**
+ * Return the end offset that is always one char after the break offset.
+ */
+ public int getEndOffset()
+ {
+ return breakOffset + 1;
+ }
+
+ /**
+ * Return the start offset that has been passed in a constructor.
+ */
+ public int getStartOffset()
+ {
+ return breakOffset;
+ }
+
+ /**
+ * Create the new instance of this view.
+ *
+ * @param element the element (inherited from the HR view)
+ * @param offset the position where the HR view has been broken
+ */
+ public Beginning(Element element, int offset)
+ {
+ super(element);
+ breakOffset = offset;
+ }
+ }
+
+ /**
+ * Creates the new HR view.
+ */
+ public HRuleView(Element element)
+ {
+ super(element);
+ }
+
+ /**
+ * Returns the ForcedBreakWeight for the vertical axis, indicating, the the
+ * view must be broken to be displayed correctly. The horizontal dash is
+ * not breakeable along the Y axis.
+ */
+ public int getBreakWeight(int axis, float pos, float len)
+ {
+ if (axis == X_AXIS && ((getEndOffset() - getStartOffset()) > 1))
+ return ForcedBreakWeight;
+ else
+ return BadBreakWeight;
+ }
+
+ /**
+ * Draws the double line, upped black and the lower light gray.
+ */
+ public void paint(Graphics g, Shape a)
+ {
+ Rectangle bounds = a.getBounds();
+
+ int x = bounds.x;
+ int y = bounds.y;
+
+ int w = bounds.x + bounds.width;
+
+ // We move "half pixel up" from the actual horizontal position -
+ // this will be rounded to the closest actual int co-ordinate.
+ int h = bounds.y + (int) Math.round(bounds.height * 0.5 - 0.5);
+
+ g.setColor(Color.black);
+ g.drawLine(x, y++, w, h++);
+ g.setColor(Color.lightGray);
+ g.drawLine(x, y, w, h);
+ }
+
+ /**
+ * Break the view into this view and the invisible imaginary view that
+ * stays on the end of line that is broken by HR dash. The view is broken
+ * only if its length is longer than one (the two characters are expected
+ * in the initial length).
+ */
+ public View breakView(int axis, int offset, float pos, float len)
+ {
+ if (getEndOffset() - getStartOffset() > 1)
+ return new Beginning(getElement(), offset);
+ else
+ return this;
+ }
+
+ /**
+ * Returns the width of the container for the horizontal axis and the
+ * thickness of the dash area for the vertical axis.
+ */
+ public float getMaximumSpan(int axis)
+ {
+ if (axis == X_AXIS)
+ {
+ Component container = getContainer();
+ if (container != null)
+ return getContainer().getWidth();
+ else
+ return 640;
+ }
+ else
+ return HEIGHT;
+ }
+
+ /**
+ * Returns the same values as {@link #getMaximumSpan(int)}
+ */
+ public float getPreferredSpan(int axis)
+ {
+ return getMaximumSpan(axis);
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/HTML.java b/libjava/classpath/javax/swing/text/html/HTML.java
new file mode 100644
index 000000000..93c05daa2
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/HTML.java
@@ -0,0 +1,1253 @@
+/* HTML.java -- HTML document tag constants
+ Copyright (C) 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import java.io.Serializable;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+import javax.swing.text.AttributeSet;
+
+/**
+ * HTML attribute and tag definitions.
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class HTML
+{
+ /**
+ * Represents a HTML attribute.
+ */
+ public static final class Attribute
+ {
+ /**
+ * The action attribute
+ */
+ public static final Attribute ACTION = new Attribute("action");
+
+ /**
+ * The align attribute
+ */
+ public static final Attribute ALIGN = new Attribute("align");
+
+ /**
+ * The alink attribute
+ */
+ public static final Attribute ALINK = new Attribute("alink");
+
+ /**
+ * The alt attribute
+ */
+ public static final Attribute ALT = new Attribute("alt");
+
+ /**
+ * The archive attribute
+ */
+ public static final Attribute ARCHIVE = new Attribute("archive");
+
+ /**
+ * The background attribute
+ */
+ public static final Attribute BACKGROUND = new Attribute("background");
+
+ /**
+ * The bgcolor attribute
+ */
+ public static final Attribute BGCOLOR = new Attribute("bgcolor");
+
+ /**
+ * The border attribute
+ */
+ public static final Attribute BORDER = new Attribute("border");
+
+ /**
+ * The cellpadding attribute
+ */
+ public static final Attribute CELLPADDING = new Attribute("cellpadding");
+
+ /**
+ * The cellspacing attribute
+ */
+ public static final Attribute CELLSPACING = new Attribute("cellspacing");
+
+ /**
+ * The checked attribute
+ */
+ public static final Attribute CHECKED = new Attribute("checked");
+
+ /**
+ * The class attribute
+ */
+ public static final Attribute CLASS = new Attribute("class");
+
+ /**
+ * The classid attribute
+ */
+ public static final Attribute CLASSID = new Attribute("classid");
+
+ /**
+ * The clear attribute
+ */
+ public static final Attribute CLEAR = new Attribute("clear");
+
+ /**
+ * The code attribute
+ */
+ public static final Attribute CODE = new Attribute("code");
+
+ /**
+ * The codebase attribute
+ */
+ public static final Attribute CODEBASE = new Attribute("codebase");
+
+ /**
+ * The codetype attribute
+ */
+ public static final Attribute CODETYPE = new Attribute("codetype");
+
+ /**
+ * The color attribute
+ */
+ public static final Attribute COLOR = new Attribute("color");
+
+ /**
+ * The cols attribute
+ */
+ public static final Attribute COLS = new Attribute("cols");
+
+ /**
+ * The colspan attribute
+ */
+ public static final Attribute COLSPAN = new Attribute("colspan");
+
+ /**
+ * The comment attribute
+ */
+ public static final Attribute COMMENT = new Attribute("comment");
+
+ /**
+ * The compact attribute
+ */
+ public static final Attribute COMPACT = new Attribute("compact");
+
+ /**
+ * The content attribute
+ */
+ public static final Attribute CONTENT = new Attribute("content");
+
+ /**
+ * The coords attribute
+ */
+ public static final Attribute COORDS = new Attribute("coords");
+
+ /**
+ * The data attribute
+ */
+ public static final Attribute DATA = new Attribute("data");
+
+ /**
+ * The declare attribute
+ */
+ public static final Attribute DECLARE = new Attribute("declare");
+
+ /**
+ * The dir attribute
+ */
+ public static final Attribute DIR = new Attribute("dir");
+
+ /**
+ * The dummy attribute
+ */
+ public static final Attribute DUMMY = new Attribute("dummy");
+
+ /**
+ * The enctype attribute
+ */
+ public static final Attribute ENCTYPE = new Attribute("enctype");
+
+ /**
+ * The endtag attribute
+ */
+ public static final Attribute ENDTAG = new Attribute("endtag");
+
+ /**
+ * The face attribute
+ */
+ public static final Attribute FACE = new Attribute("face");
+
+ /**
+ * The frameborder attribute
+ */
+ public static final Attribute FRAMEBORDER = new Attribute("frameborder");
+
+ /**
+ * The halign attribute
+ */
+ public static final Attribute HALIGN = new Attribute("halign");
+
+ /**
+ * The height attribute
+ */
+ public static final Attribute HEIGHT = new Attribute("height");
+
+ /**
+ * The href attribute
+ */
+ public static final Attribute HREF = new Attribute("href");
+
+ /**
+ * The hspace attribute
+ */
+ public static final Attribute HSPACE = new Attribute("hspace");
+
+ /**
+ * The http-equiv attribute
+ */
+ public static final Attribute HTTPEQUIV = new Attribute("http-equiv");
+
+ /**
+ * The id attribute
+ */
+ public static final Attribute ID = new Attribute("id");
+
+ /**
+ * The ismap attribute
+ */
+ public static final Attribute ISMAP = new Attribute("ismap");
+
+ /**
+ * The lang attribute
+ */
+ public static final Attribute LANG = new Attribute("lang");
+
+ /**
+ * The language attribute
+ */
+ public static final Attribute LANGUAGE = new Attribute("language");
+
+ /**
+ * The link attribute
+ */
+ public static final Attribute LINK = new Attribute("link");
+
+ /**
+ * The lowsrc attribute
+ */
+ public static final Attribute LOWSRC = new Attribute("lowsrc");
+
+ /**
+ * The marginheight attribute
+ */
+ public static final Attribute MARGINHEIGHT = new Attribute("marginheight");
+
+ /**
+ * The marginwidth attribute
+ */
+ public static final Attribute MARGINWIDTH = new Attribute("marginwidth");
+
+ /**
+ * The maxlength attribute
+ */
+ public static final Attribute MAXLENGTH = new Attribute("maxlength");
+
+ /**
+ * The media attribute
+ */
+ static final Attribute MEDIA = new Attribute("media");
+
+ /**
+ * The method attribute
+ */
+ public static final Attribute METHOD = new Attribute("method");
+
+ /**
+ * The multiple attribute
+ */
+ public static final Attribute MULTIPLE = new Attribute("multiple");
+
+ /**
+ * The n attribute
+ */
+ public static final Attribute N = new Attribute("n");
+
+ /**
+ * The name attribute
+ */
+ public static final Attribute NAME = new Attribute("name");
+
+ /**
+ * The nohref attribute
+ */
+ public static final Attribute NOHREF = new Attribute("nohref");
+
+ /**
+ * The noresize attribute
+ */
+ public static final Attribute NORESIZE = new Attribute("noresize");
+
+ /**
+ * The noshade attribute
+ */
+ public static final Attribute NOSHADE = new Attribute("noshade");
+
+ /**
+ * The nowrap attribute
+ */
+ public static final Attribute NOWRAP = new Attribute("nowrap");
+
+ /**
+ * The prompt attribute
+ */
+ public static final Attribute PROMPT = new Attribute("prompt");
+
+ /**
+ * The rel attribute
+ */
+ public static final Attribute REL = new Attribute("rel");
+
+ /**
+ * The rev attribute
+ */
+ public static final Attribute REV = new Attribute("rev");
+
+ /**
+ * The rows attribute
+ */
+ public static final Attribute ROWS = new Attribute("rows");
+
+ /**
+ * The rowspan attribute
+ */
+ public static final Attribute ROWSPAN = new Attribute("rowspan");
+
+ /**
+ * The scrolling attribute
+ */
+ public static final Attribute SCROLLING = new Attribute("scrolling");
+
+ /**
+ * The selected attribute
+ */
+ public static final Attribute SELECTED = new Attribute("selected");
+
+ /**
+ * The shape attribute
+ */
+ public static final Attribute SHAPE = new Attribute("shape");
+
+ /**
+ * The shapes attribute
+ */
+ public static final Attribute SHAPES = new Attribute("shapes");
+
+ /**
+ * The size attribute
+ */
+ public static final Attribute SIZE = new Attribute("size");
+
+ /**
+ * The src attribute
+ */
+ public static final Attribute SRC = new Attribute("src");
+
+ /**
+ * The standby attribute
+ */
+ public static final Attribute STANDBY = new Attribute("standby");
+
+ /**
+ * The start attribute
+ */
+ public static final Attribute START = new Attribute("start");
+
+ /**
+ * The style attribute
+ */
+ public static final Attribute STYLE = new Attribute("style");
+
+ /**
+ * The target attribute
+ */
+ public static final Attribute TARGET = new Attribute("target");
+
+ /**
+ * The text attribute
+ */
+ public static final Attribute TEXT = new Attribute("text");
+
+ /**
+ * The title attribute
+ */
+ public static final Attribute TITLE = new Attribute("title");
+
+ /**
+ * The type attribute
+ */
+ public static final Attribute TYPE = new Attribute("type");
+
+ /**
+ * The usemap attribute
+ */
+ public static final Attribute USEMAP = new Attribute("usemap");
+
+ /**
+ * The valign attribute
+ */
+ public static final Attribute VALIGN = new Attribute("valign");
+
+ /**
+ * The value attribute
+ */
+ public static final Attribute VALUE = new Attribute("value");
+
+ /**
+ * The valuetype attribute
+ */
+ public static final Attribute VALUETYPE = new Attribute("valuetype");
+
+ /**
+ * The version attribute
+ */
+ public static final Attribute VERSION = new Attribute("version");
+
+ /**
+ * The vlink attribute
+ */
+ public static final Attribute VLINK = new Attribute("vlink");
+
+ /**
+ * The vspace attribute
+ */
+ public static final Attribute VSPACE = new Attribute("vspace");
+
+ /**
+ * The width attribute
+ */
+ public static final Attribute WIDTH = new Attribute("width");
+
+ /**
+ * This is used to reflect the pseudo class for the a tag.
+ */
+ static final Attribute PSEUDO_CLASS = new Attribute("_pseudo");
+
+ /**
+ * This is used to reflect the dynamic class for the a tag.
+ */
+ static final Attribute DYNAMIC_CLASS = new Attribute("_dynamic");
+
+ /**
+ * The attribute name.
+ */
+ private final String name;
+
+ /**
+ * Creates the attribute with the given name.
+ */
+ private Attribute(String a_name)
+ {
+ name = a_name;
+ }
+
+ /**
+ * Returns the attribute name. The names of the built-in attributes
+ * are always returned in lowercase.
+ */
+ public String toString()
+ {
+ return name;
+ }
+
+ /**
+ * Return an array of all attributes, declared in the HTML.Attribute
+ * class. WARNING: attributes are the only public fields,
+ * expected in this class.
+ */
+ static Attribute[] getAllAttributes()
+ {
+ Field[] f = Attribute.class.getFields();
+ Attribute[] attrs = new Attribute[ f.length ];
+ Field x;
+ int p = 0;
+ Attribute a;
+
+ for (int i = 0; i < f.length; i++)
+ {
+ x = f [ i ];
+
+ if ((x.getModifiers() & Modifier.STATIC) != 0)
+ {
+ if (x.getType().equals(Attribute.class))
+ {
+ try
+ {
+ a = (Attribute) x.get(null);
+ attrs [ p++ ] = a;
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace(System.err);
+ throw new Error("This should never happen, report a bug");
+ }
+ }
+ }
+ }
+
+ return attrs;
+ }
+ }
+
+ /**
+ * Represents a HTML tag.
+ */
+ public static class Tag
+ {
+ /**
+ * The &lt;a&gt; tag
+ */
+ public static final Tag A = new Tag("a");
+
+ /**
+ * The &lt;address&gt; tag
+ */
+ public static final Tag ADDRESS = new Tag("address");
+
+ /**
+ * The &lt;applet&gt; tag
+ */
+ public static final Tag APPLET = new Tag("applet");
+
+ /**
+ * The &lt;area&gt; tag
+ */
+ public static final Tag AREA = new Tag("area");
+
+ /**
+ * The &lt;b&gt; tag
+ */
+ public static final Tag B = new Tag("b");
+
+ /**
+ * The &lt;base&gt; tag
+ */
+ public static final Tag BASE = new Tag("base");
+
+ /**
+ * The &lt;basefont&gt; tag
+ */
+ public static final Tag BASEFONT = new Tag("basefont");
+
+ /**
+ * The &lt;big&gt; tag
+ */
+ public static final Tag BIG = new Tag("big");
+
+ /**
+ * The &lt;blockquote&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag BLOCKQUOTE = new Tag("blockquote", BREAKS | BLOCK);
+
+ /**
+ * The &lt;body&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag BODY = new Tag("body", BREAKS | BLOCK);
+
+ /**
+ * The &lt;br&gt; tag , breaks flow.
+ */
+ public static final Tag BR = new Tag("br", BREAKS);
+
+ /**
+ * The &lt;caption&gt; tag
+ */
+ public static final Tag CAPTION = new Tag("caption");
+
+ /**
+ * The &lt;center&gt; tag , breaks flow.
+ */
+ public static final Tag CENTER = new Tag("center", BREAKS);
+
+ /**
+ * The &lt;cite&gt; tag
+ */
+ public static final Tag CITE = new Tag("cite");
+
+ /**
+ * The &lt;code&gt; tag
+ */
+ public static final Tag CODE = new Tag("code");
+
+ /**
+ * The &lt;dd&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag DD = new Tag("dd", BREAKS | BLOCK);
+
+ /**
+ * The &lt;dfn&gt; tag
+ */
+ public static final Tag DFN = new Tag("dfn");
+
+ /**
+ * The &lt;dir&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag DIR = new Tag("dir", BREAKS | BLOCK);
+
+ /**
+ * The &lt;div&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag DIV = new Tag("div", BREAKS | BLOCK);
+
+ /**
+ * The &lt;dl&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag DL = new Tag("dl", BREAKS | BLOCK);
+
+ /**
+ * The &lt;dt&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag DT = new Tag("dt", BREAKS | BLOCK);
+
+ /**
+ * The &lt;em&gt; tag
+ */
+ public static final Tag EM = new Tag("em");
+
+ /**
+ * The &lt;font&gt; tag
+ */
+ public static final Tag FONT = new Tag("font");
+
+ /**
+ * The &lt;form&gt; tag , breaks flow.
+ */
+ public static final Tag FORM = new Tag("form", BREAKS);
+
+ /**
+ * The &lt;frame&gt; tag
+ */
+ public static final Tag FRAME = new Tag("frame");
+
+ /**
+ * The &lt;frameset&gt; tag
+ */
+ public static final Tag FRAMESET = new Tag("frameset");
+
+ /**
+ * The &lt;h1&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag H1 = new Tag("h1", BREAKS | BLOCK);
+
+ /**
+ * The &lt;h2&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag H2 = new Tag("h2", BREAKS | BLOCK);
+
+ /**
+ * The &lt;h3&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag H3 = new Tag("h3", BREAKS | BLOCK);
+
+ /**
+ * The &lt;h4&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag H4 = new Tag("h4", BREAKS | BLOCK);
+
+ /**
+ * The &lt;h5&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag H5 = new Tag("h5", BREAKS | BLOCK);
+
+ /**
+ * The &lt;h6&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag H6 = new Tag("h6", BREAKS | BLOCK);
+
+ /**
+ * The &lt;head&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag HEAD = new Tag("head", BREAKS | BLOCK);
+
+ /**
+ * The &lt;hr&gt; tag , breaks flow.
+ */
+ public static final Tag HR = new Tag("hr", BREAKS);
+
+ /**
+ * The &lt;html&gt; tag , breaks flow.
+ */
+ public static final Tag HTML = new Tag("html", BREAKS);
+
+ /**
+ * The &lt;i&gt; tag
+ */
+ public static final Tag I = new Tag("i");
+
+ /**
+ * The &lt;img&gt; tag
+ */
+ public static final Tag IMG = new Tag("img");
+
+ /**
+ * The &lt;input&gt; tag
+ */
+ public static final Tag INPUT = new Tag("input");
+
+ /**
+ * The &lt;isindex&gt; tag , breaks flow.
+ */
+ public static final Tag ISINDEX = new Tag("isindex", BREAKS);
+
+ /**
+ * The &lt;kbd&gt; tag
+ */
+ public static final Tag KBD = new Tag("kbd");
+
+ /**
+ * The &lt;li&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag LI = new Tag("li", BREAKS | BLOCK);
+
+ /**
+ * The &lt;link&gt; tag
+ */
+ public static final Tag LINK = new Tag("link");
+
+ /**
+ * The &lt;map&gt; tag
+ */
+ public static final Tag MAP = new Tag("map");
+
+ /**
+ * The &lt;menu&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag MENU = new Tag("menu", BREAKS | BLOCK);
+
+ /**
+ * The &lt;meta&gt; tag
+ */
+ public static final Tag META = new Tag("meta");
+
+ /**
+ * The &lt;nobr&gt; tag
+ */
+ static final Tag NOBR = new Tag("nobr");
+
+ /**
+ * The &lt;noframes&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag NOFRAMES = new Tag("noframes", BREAKS | BLOCK);
+
+ /**
+ * The &lt;object&gt; tag
+ */
+ public static final Tag OBJECT = new Tag("object");
+
+ /**
+ * The &lt;ol&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag OL = new Tag("ol", BREAKS | BLOCK);
+
+ /**
+ * The &lt;option&gt; tag
+ */
+ public static final Tag OPTION = new Tag("option");
+
+ /**
+ * The &lt;p&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag P = new Tag("p", BREAKS | BLOCK);
+
+ /**
+ * The &lt;param&gt; tag
+ */
+ public static final Tag PARAM = new Tag("param");
+
+ /**
+ * The &lt;pre&gt; tag , breaks flow, block tag, preformatted.
+ */
+ public static final Tag PRE = new Tag("pre", BREAKS | BLOCK | PREFORMATTED);
+
+ /**
+ * The &lt;s&gt; tag
+ */
+ public static final Tag S = new Tag("s");
+
+ /**
+ * The &lt;samp&gt; tag
+ */
+ public static final Tag SAMP = new Tag("samp");
+
+ /**
+ * The &lt;script&gt; tag
+ */
+ public static final Tag SCRIPT = new Tag("script");
+
+ /**
+ * The &lt;select&gt; tag
+ */
+ public static final Tag SELECT = new Tag("select");
+
+ /**
+ * The &lt;small&gt; tag
+ */
+ public static final Tag SMALL = new Tag("small");
+
+ /**
+ * The &lt;span&gt; tag
+ */
+ public static final Tag SPAN = new Tag("span");
+
+ /**
+ * The &lt;strike&gt; tag
+ */
+ public static final Tag STRIKE = new Tag("strike");
+
+ /**
+ * The &lt;strong&gt; tag
+ */
+ public static final Tag STRONG = new Tag("strong");
+
+ /**
+ * The &lt;style&gt; tag
+ */
+ public static final Tag STYLE = new Tag("style");
+
+ /**
+ * The &lt;sub&gt; tag
+ */
+ public static final Tag SUB = new Tag("sub");
+
+ /**
+ * The &lt;sup&gt; tag
+ */
+ public static final Tag SUP = new Tag("sup");
+
+ /**
+ * The &lt;table&gt; tag , block tag.
+ */
+ public static final Tag TABLE = new Tag("table", BLOCK);
+
+ /**
+ * The &lt;td&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag TD = new Tag("td", BREAKS | BLOCK);
+
+ /**
+ * The &lt;textarea&gt; tag , preformatted.
+ */
+ public static final Tag TEXTAREA = new Tag("textarea", PREFORMATTED);
+
+ /**
+ * The &lt;th&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag TH = new Tag("th", BREAKS | BLOCK);
+
+ /**
+ * The &lt;title&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag TITLE = new Tag("title", BREAKS | BLOCK);
+
+ /**
+ * The &lt;tr&gt; tag , block tag.
+ */
+ public static final Tag TR = new Tag("tr", BLOCK);
+
+ /**
+ * The &lt;tt&gt; tag
+ */
+ public static final Tag TT = new Tag("tt");
+
+ /**
+ * The &lt;u&gt; tag
+ */
+ public static final Tag U = new Tag("u");
+
+ /**
+ * The &lt;ul&gt; tag , breaks flow, block tag.
+ */
+ public static final Tag UL = new Tag("ul", BREAKS | BLOCK);
+
+ /**
+ * The &lt;var&gt; tag
+ */
+ public static final Tag VAR = new Tag("var");
+
+ /* Special tags */
+
+ /**
+ * Total number of syntetic tags, delared in the Tag class.
+ * This must be adjusted if the new synthetic tags are declared.
+ * Otherwise the HTML.getAllTags() will not work as expected.
+ */
+ private static final int TOTAL_SYNTHETIC_TAGS = 3;
+
+ /**
+ * All comments are labeled with this tag.
+ * This tag is not included into the array, returned by getAllTags().
+ * toString() returns 'comment'. HTML reader synthesizes this tag.
+ */
+ public static final Tag COMMENT = new Tag("comment", SYNTHETIC);
+
+ /**
+ * All text content is labeled with this tag.
+ * This tag is not included into the array, returned by getAllTags().
+ * toString() returns 'content'. HTML reader synthesizes this tag.
+ */
+ public static final Tag CONTENT = new Tag("content", SYNTHETIC);
+
+ /**
+ * All text content must be in a paragraph element.
+ * If a paragraph didn't exist when content was encountered,
+ * a paragraph is manufactured.
+ * toString() returns 'p-implied'. HTML reader synthesizes this tag.
+ */
+ public static final Tag IMPLIED = new Tag("p-implied", SYNTHETIC);
+ final String name;
+ final int flags;
+
+ /**
+ * Create the unitialised instance of HTML.Tag.
+ *
+ * The {@link #breaksFlow()}, {@link #isBlock()}
+ * and {@link #isPreformatted()} will always return false.
+ * The {@link #toString()} will return <code>null</code>.
+ *
+ * @since 1.3
+ */
+ public Tag()
+ {
+ name = null;
+ flags = 0;
+ }
+
+ /**
+ * Creates a new Tag with the specified id, and with causesBreak
+ * and isBlock set to false.
+ */
+ protected Tag(String id)
+ {
+ name = id;
+ flags = 0;
+ }
+
+ /**
+ * Creates a new Tag with the specified tag name and
+ * causesBreak and isBlock properties.
+ */
+ protected Tag(String id, boolean causesBreak, boolean isBlock)
+ {
+ int f = 0;
+
+ if (causesBreak)
+ {
+ f |= BREAKS;
+ }
+
+ if (isBlock)
+ {
+ f |= BLOCK;
+ }
+
+ flags = f;
+ name = id;
+ }
+
+ /**
+ * Create a tag taking flags.
+ */
+ Tag(String id, int a_flags)
+ {
+ name = id;
+ flags = a_flags;
+ }
+
+ /**
+ * Returns true if this tag is a block tag, which is a tag used to
+ * add structure to a document.
+ */
+ public boolean isBlock()
+ {
+ return (flags & BLOCK) != 0;
+ }
+
+ /**
+ * Returns true if this tag is pre-formatted, which is true if
+ * the tag is either PRE or TEXTAREA
+ */
+ public boolean isPreformatted()
+ {
+ return (flags & PREFORMATTED) != 0;
+ }
+
+ /**
+ * Returns true if this tag causes a line break to the flow of text
+ */
+ public boolean breaksFlow()
+ {
+ return (flags & BREAKS) != 0;
+ }
+
+ /**
+ * Returns the tag name. The names of the built-in tags are always
+ * returned in lowercase.
+ */
+ public String toString()
+ {
+ return name;
+ }
+
+ /**
+ * Return an array of HTML tags, declared in HTML.Tag class.
+ * WARNING: This method expects that the Tags are the only
+ * public fields declared in the Tag class.
+ */
+ static Tag[] getAllTags()
+ {
+ Field[] f = Tag.class.getFields();
+ Field x;
+
+ // The syntetic tags are not included.
+ Tag[] tags = new Tag[ f.length - TOTAL_SYNTHETIC_TAGS ];
+ int p = 0;
+ Tag t;
+
+ for (int i = 0; i < f.length; i++)
+ {
+ x = f [ i ];
+
+ if ((x.getModifiers() & Modifier.STATIC) != 0)
+ {
+ if (x.getType().equals(Tag.class))
+ {
+ try
+ {
+ t = (Tag) x.get(null);
+
+ if (!t.isSyntetic())
+ {
+ tags [ p++ ] = t;
+ }
+ }
+ catch (IllegalAccessException ex)
+ {
+ unexpected(ex);
+ }
+ catch (IllegalArgumentException ex)
+ {
+ unexpected(ex);
+ }
+ }
+ }
+ }
+
+ return tags;
+ }
+
+ /**
+ * Returns true for tags, generated by the html reader
+ * (COMMENT, CONTENT and IMPLIED).
+ */
+ boolean isSyntetic()
+ {
+ return (flags & SYNTHETIC) != 0;
+ }
+
+ private static void unexpected(Exception ex)
+ throws Error
+ {
+ throw new Error("This should never happen, report a bug", ex);
+ }
+ }
+
+ /**
+ * Represents an unknown HTML tag.
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+ public static class UnknownTag
+ extends Tag
+ implements Serializable
+ {
+ private static final long serialVersionUID = -1534369342247250625L;
+
+ /**
+ * Creates a new UnknownTag with the specified name
+ * @param name The tag name.
+ *
+ */
+ public UnknownTag(String name)
+ {
+ super(name);
+ }
+ }
+
+ /**
+ * This value is returned for attributes without value that have no
+ * default value defined in the DTD.
+ */
+ public static final String NULL_ATTRIBUTE_VALUE = "#DEFAULT";
+
+ /* Package level html tag flags */
+ static final int BREAKS = 1;
+ static final int BLOCK = 2;
+ static final int PREFORMATTED = 4;
+ static final int SYNTHETIC = 8;
+ private static Map<String,Tag> tagMap;
+ private static Map<String,Attribute> attrMap;
+
+ /**
+ * The public constructor (does nothing). It it seldom required to have
+ * an instance of this class, because all public fields and methods
+ * are static.
+ */
+ public HTML()
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Returns the set of the recognized HTML attributes.
+ */
+ public static HTML.Attribute[] getAllAttributeKeys()
+ {
+ return Attribute.getAllAttributes();
+ }
+
+ /**
+ * Returns the set of actual HTML tags that are recognized by
+ * the default HTML reader. The returned array does not include the
+ * COMMENT, CONTENT and IMPLIED tags.
+ */
+ public static HTML.Tag[] getAllTags()
+ {
+ return Tag.getAllTags();
+ }
+
+ /**
+ * Returns an htl attribute constant for the given attribute name.
+ * @param attName the attribute name, case insensitive
+ */
+ public static Attribute getAttributeKey(String attName)
+ {
+ if (attrMap == null)
+ {
+ // Create the map on demand.
+ attrMap = new TreeMap<String,Attribute>();
+
+ Attribute[] attrs = getAllAttributeKeys();
+
+ for (int i = 0; i < attrs.length; i++)
+ {
+ attrMap.put(attrs [ i ].toString(), attrs [ i ]);
+ }
+ }
+
+ return attrMap.get(attName.toLowerCase());
+ }
+
+ /**
+ * Searches the value of given attribute in the provided set.
+ * If the value is found (String type expected), tries to parse it as
+ * an integer value. If succeded, returns the obtained integer value.
+ *
+ * For example:<p><code>
+ * SimpleAttributeSet ase = new SimpleAttributeSet();
+ * ase.addAttribute(HTML.getAttributeKey("size"),"222");
+ * System.out.println(
+ * HTML.getIntegerAttributeValue
+ * (ase, HTML.getAttributeKey("size"), 333)); // prints "222"
+ * System.out.println(
+ * HTML.getIntegerAttributeValue
+ * (ase, HTML.getAttributeKey("width"), 333)); // prints "333".
+ * </code></p>
+ *
+ *
+ * @param set The attribute set to search in. If the set contains the
+ * given attribute, it must by a type of String.
+ * @param attribute The html attribute to search in
+ * @param defaultValue The value that is returned if the attribute is not
+ * found in the given set or if the NumberFormatException was thrown
+ * during the parsing.
+ */
+ public static int getIntegerAttributeValue(AttributeSet set,
+ HTML.Attribute attribute,
+ int defaultValue
+ )
+ {
+ Object v = set.getAttribute(attribute);
+
+ if (v == null)
+ {
+ return defaultValue;
+ }
+
+ try
+ {
+ return Integer.parseInt(v.toString().trim());
+ }
+ catch (Exception ex)
+ {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Returns a HTML tag constant for the given HTML attribute name.
+ * If the tag is unknown, the null is returned.
+ * @param tagName the tag name, case insensitive
+ */
+ public static Tag getTag(String tagName)
+ {
+ if (tagMap == null)
+ {
+ // Create the mao on demand.
+ tagMap = new TreeMap<String,Tag>();
+
+ Tag[] tags = getAllTags();
+
+ for (int i = 0; i < tags.length; i++)
+ {
+ tagMap.put(tags [ i ].toString(), tags [ i ]);
+ }
+ }
+
+ return tagMap.get(tagName.toLowerCase());
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/HTMLDocument.java b/libjava/classpath/javax/swing/text/html/HTMLDocument.java
new file mode 100644
index 000000000..9545be4e8
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/HTMLDocument.java
@@ -0,0 +1,2298 @@
+/* HTMLDocument.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 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.ButtonGroup;
+import javax.swing.DefaultButtonModel;
+import javax.swing.JEditorPane;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.UndoableEditEvent;
+import javax.swing.text.AbstractDocument;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.DefaultStyledDocument;
+import javax.swing.text.Element;
+import javax.swing.text.ElementIterator;
+import javax.swing.text.GapContent;
+import javax.swing.text.MutableAttributeSet;
+import javax.swing.text.PlainDocument;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.html.HTML.Tag;
+
+/**
+ * Represents the HTML document that is constructed by defining the text and
+ * other components (images, buttons, etc) in HTML language. This class can
+ * becomes the default document for {@link JEditorPane} after setting its
+ * content type to "text/html". HTML document also serves as an intermediate
+ * data structure when it is needed to parse HTML and then obtain the content of
+ * the certain types of tags. This class also has methods for modifying the HTML
+ * content.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ * @author Anthony Balkissoon (abalkiss@redhat.com)
+ * @author Lillian Angel (langel@redhat.com)
+ */
+public class HTMLDocument extends DefaultStyledDocument
+{
+ /** A key for document properies. The value for the key is
+ * a Vector of Strings of comments not found in the body.
+ */
+ public static final String AdditionalComments = "AdditionalComments";
+ URL baseURL = null;
+ boolean preservesUnknownTags = true;
+ int tokenThreshold = Integer.MAX_VALUE;
+ HTMLEditorKit.Parser parser;
+
+ /**
+ * Indicates whether this document is inside a frame or not.
+ */
+ private boolean frameDocument;
+
+ /**
+ * Package private to avoid accessor methods.
+ */
+ String baseTarget;
+
+ /**
+ * Constructs an HTML document using the default buffer size and a default
+ * StyleSheet.
+ */
+ public HTMLDocument()
+ {
+ this(new GapContent(BUFFER_SIZE_DEFAULT), new StyleSheet());
+ }
+
+ /**
+ * Constructs an HTML document with the default content storage
+ * implementation and the specified style/attribute storage mechanism.
+ *
+ * @param styles - the style sheet
+ */
+ public HTMLDocument(StyleSheet styles)
+ {
+ this(new GapContent(BUFFER_SIZE_DEFAULT), styles);
+ }
+
+ /**
+ * Constructs an HTML document with the given content storage implementation
+ * and the given style/attribute storage mechanism.
+ *
+ * @param c - the document's content
+ * @param styles - the style sheet
+ */
+ public HTMLDocument(AbstractDocument.Content c, StyleSheet styles)
+ {
+ super(c, styles);
+ }
+
+ /**
+ * Gets the style sheet with the document display rules (CSS) that were specified
+ * in the HTML document.
+ *
+ * @return - the style sheet
+ */
+ public StyleSheet getStyleSheet()
+ {
+ return (StyleSheet) getAttributeContext();
+ }
+
+ /**
+ * This method creates a root element for the new document.
+ *
+ * @return the new default root
+ */
+ protected AbstractElement createDefaultRoot()
+ {
+ AbstractDocument.AttributeContext ctx = getAttributeContext();
+
+ // Create html element.
+ AttributeSet atts = ctx.getEmptySet();
+ atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, HTML.Tag.HTML);
+ BranchElement html = (BranchElement) createBranchElement(null, atts);
+
+ // Create body element.
+ atts = ctx.getEmptySet();
+ atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, HTML.Tag.BODY);
+ BranchElement body = (BranchElement) createBranchElement(html, atts);
+ html.replace(0, 0, new Element[] { body });
+
+ // Create p element.
+ atts = ctx.getEmptySet();
+ atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, HTML.Tag.P);
+ BranchElement p = (BranchElement) createBranchElement(body, atts);
+ body.replace(0, 0, new Element[] { p });
+
+ // Create an empty leaf element.
+ atts = ctx.getEmptySet();
+ atts = ctx.addAttribute(atts, StyleConstants.NameAttribute,
+ HTML.Tag.CONTENT);
+ Element leaf = createLeafElement(p, atts, 0, 1);
+ p.replace(0, 0, new Element[]{ leaf });
+
+ return html;
+ }
+
+ /**
+ * This method returns an HTMLDocument.RunElement object attached to
+ * parent representing a run of text from p0 to p1. The run has
+ * attributes described by a.
+ *
+ * @param parent - the parent element
+ * @param a - the attributes for the element
+ * @param p0 - the beginning of the range >= 0
+ * @param p1 - the end of the range >= p0
+ *
+ * @return the new element
+ */
+ protected Element createLeafElement(Element parent, AttributeSet a, int p0,
+ int p1)
+ {
+ return new RunElement(parent, a, p0, p1);
+ }
+
+ /**
+ * This method returns an HTMLDocument.BlockElement object representing the
+ * attribute set a and attached to parent.
+ *
+ * @param parent - the parent element
+ * @param a - the attributes for the element
+ *
+ * @return the new element
+ */
+ protected Element createBranchElement(Element parent, AttributeSet a)
+ {
+ return new BlockElement(parent, a);
+ }
+
+ /**
+ * Returns the parser used by this HTMLDocument to insert HTML.
+ *
+ * @return the parser used by this HTMLDocument to insert HTML.
+ */
+ public HTMLEditorKit.Parser getParser()
+ {
+ return parser;
+ }
+
+ /**
+ * Sets the parser used by this HTMLDocument to insert HTML.
+ *
+ * @param p the parser to use
+ */
+ public void setParser (HTMLEditorKit.Parser p)
+ {
+ parser = p;
+ }
+ /**
+ * Sets the number of tokens to buffer before trying to display the
+ * Document.
+ *
+ * @param n the number of tokens to buffer
+ */
+ public void setTokenThreshold (int n)
+ {
+ tokenThreshold = n;
+ }
+
+ /**
+ * Returns the number of tokens that are buffered before the document
+ * is rendered.
+ *
+ * @return the number of tokens buffered
+ */
+ public int getTokenThreshold ()
+ {
+ return tokenThreshold;
+ }
+
+ /**
+ * Returns the location against which to resolve relative URLs.
+ * This is the document's URL if the document was loaded from a URL.
+ * If a <code>base</code> tag is found, it will be used.
+ * @return the base URL
+ */
+ public URL getBase()
+ {
+ return baseURL;
+ }
+
+ /**
+ * Sets the location against which to resolve relative URLs.
+ * @param u the new base URL
+ */
+ public void setBase(URL u)
+ {
+ baseURL = u;
+ getStyleSheet().setBase(u);
+ }
+
+ /**
+ * Returns whether or not the parser preserves unknown HTML tags.
+ * @return true if the parser preserves unknown tags
+ */
+ public boolean getPreservesUnknownTags()
+ {
+ return preservesUnknownTags;
+ }
+
+ /**
+ * Sets the behaviour of the parser when it encounters unknown HTML tags.
+ * @param preservesTags true if the parser should preserve unknown tags.
+ */
+ public void setPreservesUnknownTags(boolean preservesTags)
+ {
+ preservesUnknownTags = preservesTags;
+ }
+
+ /**
+ * An iterator to iterate through LeafElements in the document.
+ */
+ class LeafIterator extends Iterator
+ {
+ HTML.Tag tag;
+ HTMLDocument doc;
+ ElementIterator it;
+
+ public LeafIterator (HTML.Tag t, HTMLDocument d)
+ {
+ doc = d;
+ tag = t;
+ it = new ElementIterator(doc);
+ }
+
+ /**
+ * Return the attributes for the tag associated with this iteartor
+ * @return the AttributeSet
+ */
+ public AttributeSet getAttributes()
+ {
+ if (it.current() != null)
+ return it.current().getAttributes();
+ return null;
+ }
+
+ /**
+ * Get the end of the range for the current occurrence of the tag
+ * being defined and having the same attributes.
+ * @return the end of the range
+ */
+ public int getEndOffset()
+ {
+ if (it.current() != null)
+ return it.current().getEndOffset();
+ return -1;
+ }
+
+ /**
+ * Get the start of the range for the current occurrence of the tag
+ * being defined and having the same attributes.
+ * @return the start of the range (-1 if it can't be found).
+ */
+
+ public int getStartOffset()
+ {
+ if (it.current() != null)
+ return it.current().getStartOffset();
+ return -1;
+ }
+
+ /**
+ * Advance the iterator to the next LeafElement .
+ */
+ public void next()
+ {
+ it.next();
+ while (it.current()!= null && !it.current().isLeaf())
+ it.next();
+ }
+
+ /**
+ * Indicates whether or not the iterator currently represents an occurrence
+ * of the tag.
+ * @return true if the iterator currently represents an occurrence of the
+ * tag.
+ */
+ public boolean isValid()
+ {
+ return it.current() != null;
+ }
+
+ /**
+ * Type of tag for this iterator.
+ */
+ public Tag getTag()
+ {
+ return tag;
+ }
+
+ }
+
+ public void processHTMLFrameHyperlinkEvent(HTMLFrameHyperlinkEvent event)
+ {
+ String target = event.getTarget();
+ Element el = event.getSourceElement();
+ URL url = event.getURL();
+ if (target.equals("_self"))
+ {
+ updateFrame(el, url);
+ }
+ else if (target.equals("_parent"))
+ {
+ updateFrameSet(el.getParentElement(), url);
+ }
+ else
+ {
+ Element targetFrame = findFrame(target);
+ if (targetFrame != null)
+ updateFrame(targetFrame, url);
+ }
+ }
+
+ /**
+ * Finds the named frame inside this document.
+ *
+ * @param target the name to look for
+ *
+ * @return the frame if there is a matching frame, <code>null</code>
+ * otherwise
+ */
+ private Element findFrame(String target)
+ {
+ ElementIterator i = new ElementIterator(this);
+ Element next = null;
+ while ((next = i.next()) != null)
+ {
+ AttributeSet atts = next.getAttributes();
+ if (atts.getAttribute(StyleConstants.NameAttribute) == HTML.Tag.FRAME)
+ {
+ String name = (String) atts.getAttribute(HTML.Attribute.NAME);
+ if (name != null && name.equals(target))
+ break;
+ }
+ }
+ return next;
+ }
+
+ /**
+ * Updates the frame that is represented by the specified element to
+ * refer to the specified URL.
+ *
+ * @param el the element
+ * @param url the new url
+ */
+ private void updateFrame(Element el, URL url)
+ {
+ try
+ {
+ writeLock();
+ DefaultDocumentEvent ev =
+ new DefaultDocumentEvent(el.getStartOffset(), 1,
+ DocumentEvent.EventType.CHANGE);
+ AttributeSet elAtts = el.getAttributes();
+ AttributeSet copy = elAtts.copyAttributes();
+ MutableAttributeSet matts = (MutableAttributeSet) elAtts;
+ ev.addEdit(new AttributeUndoableEdit(el, copy, false));
+ matts.removeAttribute(HTML.Attribute.SRC);
+ matts.addAttribute(HTML.Attribute.SRC, url.toString());
+ ev.end();
+ fireChangedUpdate(ev);
+ fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
+ }
+ finally
+ {
+ writeUnlock();
+ }
+ }
+
+ /**
+ * Updates the frameset that is represented by the specified element
+ * to create a frame that refers to the specified URL.
+ *
+ * @param el the element
+ * @param url the url
+ */
+ private void updateFrameSet(Element el, URL url)
+ {
+ int start = el.getStartOffset();
+ int end = el.getEndOffset();
+
+ StringBuilder html = new StringBuilder();
+ html.append("<frame");
+ if (url != null)
+ {
+ html.append(" src=\"");
+ html.append(url.toString());
+ html.append("\"");
+ }
+ html.append('>');
+ if (getParser() == null)
+ setParser(new HTMLEditorKit().getParser());
+ try
+ {
+ setOuterHTML(el, html.toString());
+ }
+ catch (BadLocationException ex)
+ {
+ ex.printStackTrace();
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+ /**
+ * Gets an iterator for the given HTML.Tag.
+ * @param t the requested HTML.Tag
+ * @return the Iterator
+ */
+ public HTMLDocument.Iterator getIterator (HTML.Tag t)
+ {
+ return new HTMLDocument.LeafIterator(t, this);
+ }
+
+ /**
+ * An iterator over a particular type of tag.
+ */
+ public abstract static class Iterator
+ {
+ /**
+ * Return the attribute set for this tag.
+ * @return the <code>AttributeSet</code> (null if none found).
+ */
+ public abstract AttributeSet getAttributes();
+
+ /**
+ * Get the end of the range for the current occurrence of the tag
+ * being defined and having the same attributes.
+ * @return the end of the range
+ */
+ public abstract int getEndOffset();
+
+ /**
+ * Get the start of the range for the current occurrence of the tag
+ * being defined and having the same attributes.
+ * @return the start of the range (-1 if it can't be found).
+ */
+ public abstract int getStartOffset();
+
+ /**
+ * Move the iterator forward.
+ */
+ public abstract void next();
+
+ /**
+ * Indicates whether or not the iterator currently represents an occurrence
+ * of the tag.
+ * @return true if the iterator currently represents an occurrence of the
+ * tag.
+ */
+ public abstract boolean isValid();
+
+ /**
+ * Type of tag this iterator represents.
+ * @return the tag.
+ */
+ public abstract HTML.Tag getTag();
+ }
+
+ public class BlockElement extends AbstractDocument.BranchElement
+ {
+ public BlockElement (Element parent, AttributeSet a)
+ {
+ super(parent, a);
+ }
+
+ /**
+ * Gets the resolving parent. Since HTML attributes are not
+ * inherited at the model level, this returns null.
+ */
+ public AttributeSet getResolveParent()
+ {
+ return null;
+ }
+
+ /**
+ * Gets the name of the element.
+ *
+ * @return the name of the element if it exists, null otherwise.
+ */
+ public String getName()
+ {
+ Object tag = getAttribute(StyleConstants.NameAttribute);
+ String name = null;
+ if (tag != null)
+ name = tag.toString();
+ if (name == null)
+ name = super.getName();
+ return name;
+ }
+ }
+
+ /**
+ * RunElement represents a section of text that has a set of
+ * HTML character level attributes assigned to it.
+ */
+ public class RunElement extends AbstractDocument.LeafElement
+ {
+
+ /**
+ * Constructs an element that has no children. It represents content
+ * within the document.
+ *
+ * @param parent - parent of this
+ * @param a - elements attributes
+ * @param start - the start offset >= 0
+ * @param end - the end offset
+ */
+ public RunElement(Element parent, AttributeSet a, int start, int end)
+ {
+ super(parent, a, start, end);
+ }
+
+ /**
+ * Gets the name of the element.
+ *
+ * @return the name of the element if it exists, null otherwise.
+ */
+ public String getName()
+ {
+ Object tag = getAttribute(StyleConstants.NameAttribute);
+ String name = null;
+ if (tag != null)
+ name = tag.toString();
+ if (name == null)
+ name = super.getName();
+ return name;
+ }
+
+ /**
+ * Gets the resolving parent. HTML attributes do not inherit at the
+ * model level, so this method returns null.
+ *
+ * @return null
+ */
+ public AttributeSet getResolveParent()
+ {
+ return null;
+ }
+ }
+
+ /**
+ * A reader to load an HTMLDocument with HTML structure.
+ *
+ * @author Anthony Balkissoon abalkiss at redhat dot com
+ */
+ public class HTMLReader extends HTMLEditorKit.ParserCallback
+ {
+ /**
+ * The maximum token threshold. We don't grow it larger than this.
+ */
+ private static final int MAX_THRESHOLD = 10000;
+
+ /**
+ * The threshold growth factor.
+ */
+ private static final int GROW_THRESHOLD = 5;
+
+ /**
+ * Holds the current character attribute set *
+ */
+ protected MutableAttributeSet charAttr = new SimpleAttributeSet();
+
+ protected Vector<ElementSpec> parseBuffer = new Vector<ElementSpec>();
+
+ /**
+ * The parse stack. It holds the current element tree path.
+ */
+ private Stack<HTML.Tag> parseStack = new Stack<HTML.Tag>();
+
+ /**
+ * A stack for character attribute sets *
+ */
+ Stack charAttrStack = new Stack();
+
+ /** A mapping between HTML.Tag objects and the actions that handle them **/
+ HashMap tagToAction;
+
+ /** Tells us whether we've received the '</html>' tag yet **/
+ boolean endHTMLEncountered = false;
+
+ /**
+ * Related to the constructor with explicit insertTag
+ */
+ int popDepth;
+
+ /**
+ * Related to the constructor with explicit insertTag
+ */
+ int pushDepth;
+
+ /**
+ * Related to the constructor with explicit insertTag
+ */
+ int offset;
+
+ /**
+ * The tag (inclusve), after that the insertion should start.
+ */
+ HTML.Tag insertTag;
+
+ /**
+ * This variable becomes true after the insert tag has been encountered.
+ */
+ boolean insertTagEncountered;
+
+
+ /** A temporary variable that helps with the printing out of debug information **/
+ boolean debug = false;
+
+ /**
+ * This is true when we are inside a pre tag.
+ */
+ boolean inPreTag = false;
+
+ /**
+ * This is true when we are inside a style tag. This will add text
+ * content inside this style tag beeing parsed as CSS.
+ *
+ * This is package private to avoid accessor methods.
+ */
+ boolean inStyleTag = false;
+
+ /**
+ * This is true when we are inside a &lt;textarea&gt; tag. Any text
+ * content will then be added to the text area.
+ *
+ * This is package private to avoid accessor methods.
+ */
+ boolean inTextArea = false;
+
+ /**
+ * This contains all stylesheets that are somehow read, either
+ * via embedded style tags, or via linked stylesheets. The
+ * elements will be String objects containing a stylesheet each.
+ */
+ ArrayList styles;
+
+ /**
+ * The document model for a textarea.
+ *
+ * This is package private to avoid accessor methods.
+ */
+ ResetablePlainDocument textAreaDocument;
+
+ /**
+ * The current model of a select tag. Can be a ComboBoxModel or a
+ * ListModel depending on the type of the select box.
+ */
+ Object selectModel;
+
+ /**
+ * The current option beeing read.
+ */
+ Option option;
+
+ /**
+ * The current number of options in the current select model.
+ */
+ int numOptions;
+
+ /**
+ * The current button groups mappings.
+ */
+ HashMap buttonGroups;
+
+ /**
+ * The token threshold. This gets increased while loading.
+ */
+ private int threshold;
+
+ public class TagAction
+ {
+ /**
+ * This method is called when a start tag is seen for one of the types
+ * of tags associated with this Action. By default this does nothing.
+ */
+ public void start(HTML.Tag t, MutableAttributeSet a)
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action. By default does nothing.
+ */
+ public void end(HTML.Tag t)
+ {
+ // Nothing to do here.
+ }
+ }
+
+ public class BlockAction 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)
+ {
+ // Tell the parse buffer to open a new block for this tag.
+ blockOpen(t, a);
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ // Tell the parse buffer to close this block.
+ blockClose(t);
+ }
+ }
+
+ public class CharacterAction 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)
+ {
+ // Put the old attribute set on the stack.
+ pushCharacterStyle();
+
+ // Initialize with link pseudo class.
+ if (t == HTML.Tag.A)
+ a.addAttribute(HTML.Attribute.PSEUDO_CLASS, "link");
+
+ // Just add the attributes in <code>a</code>.
+ charAttr.addAttribute(t, a.copyAttributes());
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ popCharacterStyle();
+ }
+ }
+
+ /**
+ * Processes elements that make up forms: &lt;input&gt;, &lt;textarea&gt;,
+ * &lt;select&gt; and &lt;option&gt;.
+ */
+ public class FormAction extends SpecialAction
+ {
+ /**
+ * 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)
+ {
+ if (t == HTML.Tag.INPUT)
+ {
+ String type = (String) a.getAttribute(HTML.Attribute.TYPE);
+ if (type == null)
+ {
+ type = "text"; // Default to 'text' when nothing was specified.
+ a.addAttribute(HTML.Attribute.TYPE, type);
+ }
+ setModel(type, a);
+ }
+ else if (t == HTML.Tag.TEXTAREA)
+ {
+ inTextArea = true;
+ textAreaDocument = new ResetablePlainDocument();
+ a.addAttribute(StyleConstants.ModelAttribute, textAreaDocument);
+ }
+ else if (t == HTML.Tag.SELECT)
+ {
+ int size = HTML.getIntegerAttributeValue(a, HTML.Attribute.SIZE,
+ 1);
+ boolean multi = a.getAttribute(HTML.Attribute.MULTIPLE) != null;
+ if (size > 1 || multi)
+ {
+ SelectListModel m = new SelectListModel();
+ if (multi)
+ m.getSelectionModel().setSelectionMode(ListSelectionModel
+ .MULTIPLE_INTERVAL_SELECTION);
+ selectModel = m;
+ }
+ else
+ {
+ selectModel = new SelectComboBoxModel();
+ }
+ a.addAttribute(StyleConstants.ModelAttribute, selectModel);
+ }
+ if (t == HTML.Tag.OPTION)
+ {
+ option = new Option(a);
+ if (selectModel instanceof SelectListModel)
+ {
+ SelectListModel m = (SelectListModel) selectModel;
+ m.addElement(option);
+ if (option.isSelected())
+ {
+ m.getSelectionModel().addSelectionInterval(numOptions,
+ numOptions);
+ m.addInitialSelection(numOptions);
+ }
+ }
+ else if (selectModel instanceof SelectComboBoxModel)
+ {
+ SelectComboBoxModel m = (SelectComboBoxModel) selectModel;
+ m.addElement(option);
+ if (option.isSelected())
+ {
+ m.setSelectedItem(option);
+ m.setInitialSelection(option);
+ }
+ }
+ numOptions++;
+ }
+ else
+ {
+ // Build the element.
+ super.start(t, a);
+ }
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ if (t == HTML.Tag.OPTION)
+ {
+ option = null;
+ }
+ else
+ {
+ if (t == HTML.Tag.TEXTAREA)
+ {
+ inTextArea = false;
+ }
+ else if (t == HTML.Tag.SELECT)
+ {
+ selectModel = null;
+ numOptions = 0;
+ }
+ // Finish the element.
+ super.end(t);
+ }
+ }
+
+ private void setModel(String type, MutableAttributeSet attrs)
+ {
+ if (type.equals("submit") || type.equals("reset")
+ || type.equals("image"))
+ {
+ // Create button.
+ attrs.addAttribute(StyleConstants.ModelAttribute,
+ new DefaultButtonModel());
+ }
+ else if (type.equals("text") || type.equals("password"))
+ {
+ String text = (String) attrs.getAttribute(HTML.Attribute.VALUE);
+ ResetablePlainDocument doc = new ResetablePlainDocument();
+ if (text != null)
+ {
+ doc.setInitialText(text);
+ try
+ {
+ doc.insertString(0, text, null);
+ }
+ catch (BadLocationException ex)
+ {
+ // Shouldn't happen.
+ assert false;
+ }
+ }
+ attrs.addAttribute(StyleConstants.ModelAttribute, doc);
+ }
+ else if (type.equals("file"))
+ {
+ attrs.addAttribute(StyleConstants.ModelAttribute,
+ new PlainDocument());
+ }
+ else if (type.equals("checkbox") || type.equals("radio"))
+ {
+ ResetableToggleButtonModel model =
+ new ResetableToggleButtonModel();
+ if (attrs.getAttribute(HTML.Attribute.SELECTED) != null)
+ {
+ model.setSelected(true);
+ model.setInitial(true);
+ }
+ if (type.equals("radio"))
+ {
+ String name = (String) attrs.getAttribute(HTML.Attribute.NAME);
+ if (name != null)
+ {
+ if (buttonGroups == null)
+ buttonGroups = new HashMap();
+ ButtonGroup group = (ButtonGroup) buttonGroups.get(name);
+ if (group == null)
+ {
+ group = new ButtonGroup();
+ buttonGroups.put(name, group);
+ }
+ model.setGroup(group);
+ }
+ }
+ attrs.addAttribute(StyleConstants.ModelAttribute, model);
+ }
+ }
+ }
+
+ /**
+ * Called for form tags.
+ */
+ class FormTagAction
+ extends BlockAction
+ {
+ /**
+ * Clears the button group mapping.
+ */
+ public void end(HTML.Tag t)
+ {
+ super.end(t);
+ buttonGroups = null;
+ }
+ }
+
+ /**
+ * This action indicates that the content between starting and closing HTML
+ * elements (like script - /script) should not be visible. The content is
+ * still inserted and can be accessed when iterating the HTML document. The
+ * parser will only fire
+ * {@link javax.swing.text.html.HTMLEditorKit.ParserCallback#handleText} for
+ * the hidden tags, regardless from that html tags the hidden section may
+ * contain.
+ */
+ public class HiddenAction
+ 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)
+ {
+ blockOpen(t, a);
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ blockClose(t);
+ }
+ }
+
+ /**
+ * Handles &lt;isindex&gt; tags.
+ */
+ public class IsindexAction 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)
+ {
+ blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet());
+ addSpecialElement(t, a);
+ blockClose(HTML.Tag.IMPLIED);
+ }
+ }
+
+ public class ParagraphAction extends BlockAction
+ {
+ /**
+ * 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)
+ {
+ super.start(t, a);
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ super.end(t);
+ }
+ }
+
+ /**
+ * This action is performed when a &lt;pre&gt; tag is parsed.
+ */
+ public class PreAction extends BlockAction
+ {
+ /**
+ * 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)
+ {
+ inPreTag = true;
+ blockOpen(t, a);
+ a.addAttribute(CSS.Attribute.WHITE_SPACE, "pre");
+ blockOpen(HTML.Tag.IMPLIED, a);
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ blockClose(HTML.Tag.IMPLIED);
+ inPreTag = false;
+ blockClose(t);
+ }
+ }
+
+ /**
+ * Inserts the elements that are represented by ths single tag with
+ * attributes (only). The closing tag, even if present, mut follow
+ * immediately after the starting tag without providing any additional
+ * information. Hence the {@link TagAction#end} method need not be
+ * overridden and still does nothing.
+ */
+ public class SpecialAction extends TagAction
+ {
+ /**
+ * The functionality is delegated to {@link HTMLReader#addSpecialElement}
+ */
+ public void start(HTML.Tag t, MutableAttributeSet a)
+ {
+ addSpecialElement(t, a);
+ }
+ }
+
+ class AreaAction 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.
+ }
+
+ /**
+ * 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.
+ }
+ }
+
+ /**
+ * Converts HTML tags to CSS attributes.
+ */
+ class ConvertAction
+ extends TagAction
+ {
+
+ public void start(HTML.Tag tag, MutableAttributeSet atts)
+ {
+ pushCharacterStyle();
+ charAttr.addAttribute(tag, atts.copyAttributes());
+ StyleSheet styleSheet = getStyleSheet();
+ // TODO: Add other tags here.
+ if (tag == HTML.Tag.FONT)
+ {
+ String color = (String) atts.getAttribute(HTML.Attribute.COLOR);
+ if (color != null)
+ styleSheet.addCSSAttribute(charAttr, CSS.Attribute.COLOR, color);
+ String face = (String) atts.getAttribute(HTML.Attribute.FACE);
+ if (face != null)
+ styleSheet.addCSSAttribute(charAttr, CSS.Attribute.FONT_FAMILY,
+ face);
+ String size = (String) atts.getAttribute(HTML.Attribute.SIZE);
+ if (size != null)
+ styleSheet.addCSSAttribute(charAttr, CSS.Attribute.FONT_SIZE,
+ size);
+ }
+ }
+
+ public void end(HTML.Tag tag)
+ {
+ popCharacterStyle();
+ }
+ }
+
+ class BaseAction 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)
+ {
+ baseTarget = (String) a.getAttribute(HTML.Attribute.TARGET);
+ }
+ }
+
+ class HeadAction extends BlockAction
+ {
+ /**
+ * 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);
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ // 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 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)
+ {
+ 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();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ 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.
+ }
+
+ /**
+ * 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 MetaAction 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.
+ }
+
+ /**
+ * 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 StyleAction 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)
+ {
+ inStyleTag = true;
+ }
+
+ /**
+ * Called when an end tag is seen for one of the types of tags associated
+ * with this Action.
+ */
+ public void end(HTML.Tag t)
+ {
+ inStyleTag = false;
+ }
+ }
+
+ class TitleAction 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.
+ }
+
+ /**
+ * 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.
+ }
+ }
+
+ public HTMLReader(int offset)
+ {
+ this (offset, 0, 0, null);
+ }
+
+ public HTMLReader(int offset, int popDepth, int pushDepth,
+ HTML.Tag insertTag)
+ {
+ this.insertTag = insertTag;
+ this.offset = offset;
+ this.popDepth = popDepth;
+ this.pushDepth = pushDepth;
+ threshold = getTokenThreshold();
+ initTags();
+ }
+
+ void initTags()
+ {
+ tagToAction = new HashMap(72);
+ CharacterAction characterAction = new CharacterAction();
+ HiddenAction hiddenAction = new HiddenAction();
+ AreaAction areaAction = new AreaAction();
+ BaseAction baseAction = new BaseAction();
+ BlockAction blockAction = new BlockAction();
+ SpecialAction specialAction = new SpecialAction();
+ ParagraphAction paragraphAction = new ParagraphAction();
+ HeadAction headAction = new HeadAction();
+ FormAction formAction = new FormAction();
+ IsindexAction isindexAction = new IsindexAction();
+ LinkAction linkAction = new LinkAction();
+ MapAction mapAction = new MapAction();
+ PreAction preAction = new PreAction();
+ MetaAction metaAction = new MetaAction();
+ StyleAction styleAction = new StyleAction();
+ TitleAction titleAction = new TitleAction();
+
+ ConvertAction convertAction = new ConvertAction();
+ tagToAction.put(HTML.Tag.A, characterAction);
+ tagToAction.put(HTML.Tag.ADDRESS, characterAction);
+ tagToAction.put(HTML.Tag.APPLET, hiddenAction);
+ tagToAction.put(HTML.Tag.AREA, areaAction);
+ tagToAction.put(HTML.Tag.B, characterAction);
+ tagToAction.put(HTML.Tag.BASE, baseAction);
+ tagToAction.put(HTML.Tag.BASEFONT, characterAction);
+ tagToAction.put(HTML.Tag.BIG, characterAction);
+ tagToAction.put(HTML.Tag.BLOCKQUOTE, blockAction);
+ tagToAction.put(HTML.Tag.BODY, blockAction);
+ tagToAction.put(HTML.Tag.BR, specialAction);
+ tagToAction.put(HTML.Tag.CAPTION, blockAction);
+ tagToAction.put(HTML.Tag.CENTER, blockAction);
+ tagToAction.put(HTML.Tag.CITE, characterAction);
+ tagToAction.put(HTML.Tag.CODE, characterAction);
+ tagToAction.put(HTML.Tag.DD, blockAction);
+ tagToAction.put(HTML.Tag.DFN, characterAction);
+ tagToAction.put(HTML.Tag.DIR, blockAction);
+ tagToAction.put(HTML.Tag.DIV, blockAction);
+ tagToAction.put(HTML.Tag.DL, blockAction);
+ tagToAction.put(HTML.Tag.DT, paragraphAction);
+ tagToAction.put(HTML.Tag.EM, characterAction);
+ tagToAction.put(HTML.Tag.FONT, convertAction);
+ tagToAction.put(HTML.Tag.FORM, new FormTagAction());
+ tagToAction.put(HTML.Tag.FRAME, specialAction);
+ tagToAction.put(HTML.Tag.FRAMESET, blockAction);
+ tagToAction.put(HTML.Tag.H1, paragraphAction);
+ tagToAction.put(HTML.Tag.H2, paragraphAction);
+ tagToAction.put(HTML.Tag.H3, paragraphAction);
+ tagToAction.put(HTML.Tag.H4, paragraphAction);
+ tagToAction.put(HTML.Tag.H5, paragraphAction);
+ tagToAction.put(HTML.Tag.H6, paragraphAction);
+ tagToAction.put(HTML.Tag.HEAD, headAction);
+ tagToAction.put(HTML.Tag.HR, specialAction);
+ tagToAction.put(HTML.Tag.HTML, blockAction);
+ tagToAction.put(HTML.Tag.I, characterAction);
+ tagToAction.put(HTML.Tag.IMG, specialAction);
+ tagToAction.put(HTML.Tag.INPUT, formAction);
+ tagToAction.put(HTML.Tag.ISINDEX, isindexAction);
+ tagToAction.put(HTML.Tag.KBD, characterAction);
+ tagToAction.put(HTML.Tag.LI, blockAction);
+ tagToAction.put(HTML.Tag.LINK, linkAction);
+ tagToAction.put(HTML.Tag.MAP, mapAction);
+ tagToAction.put(HTML.Tag.MENU, blockAction);
+ tagToAction.put(HTML.Tag.META, metaAction);
+ tagToAction.put(HTML.Tag.NOFRAMES, blockAction);
+ tagToAction.put(HTML.Tag.OBJECT, specialAction);
+ tagToAction.put(HTML.Tag.OL, blockAction);
+ tagToAction.put(HTML.Tag.OPTION, formAction);
+ tagToAction.put(HTML.Tag.P, paragraphAction);
+ tagToAction.put(HTML.Tag.PARAM, hiddenAction);
+ tagToAction.put(HTML.Tag.PRE, preAction);
+ tagToAction.put(HTML.Tag.SAMP, characterAction);
+ tagToAction.put(HTML.Tag.SCRIPT, hiddenAction);
+ tagToAction.put(HTML.Tag.SELECT, formAction);
+ tagToAction.put(HTML.Tag.SMALL, characterAction);
+ tagToAction.put(HTML.Tag.STRIKE, characterAction);
+ tagToAction.put(HTML.Tag.S, characterAction);
+ tagToAction.put(HTML.Tag.STRONG, characterAction);
+ tagToAction.put(HTML.Tag.STYLE, styleAction);
+ tagToAction.put(HTML.Tag.SUB, characterAction);
+ tagToAction.put(HTML.Tag.SUP, characterAction);
+ tagToAction.put(HTML.Tag.TABLE, blockAction);
+ tagToAction.put(HTML.Tag.TD, blockAction);
+ tagToAction.put(HTML.Tag.TEXTAREA, formAction);
+ tagToAction.put(HTML.Tag.TH, blockAction);
+ tagToAction.put(HTML.Tag.TITLE, titleAction);
+ tagToAction.put(HTML.Tag.TR, blockAction);
+ tagToAction.put(HTML.Tag.TT, characterAction);
+ tagToAction.put(HTML.Tag.U, characterAction);
+ tagToAction.put(HTML.Tag.UL, blockAction);
+ tagToAction.put(HTML.Tag.VAR, characterAction);
+ }
+
+ /**
+ * Pushes the current character style onto the stack.
+ *
+ */
+ protected void pushCharacterStyle()
+ {
+ charAttrStack.push(charAttr.copyAttributes());
+ }
+
+ /**
+ * Pops a character style off of the stack and uses it as the
+ * current character style.
+ *
+ */
+ protected void popCharacterStyle()
+ {
+ if (!charAttrStack.isEmpty())
+ charAttr = (MutableAttributeSet) charAttrStack.pop();
+ }
+
+ /**
+ * Registers a given tag with a given Action. All of the well-known tags
+ * are registered by default, but this method can change their behaviour
+ * or add support for custom or currently unsupported tags.
+ *
+ * @param t the Tag to register
+ * @param a the Action for the Tag
+ */
+ protected void registerTag(HTML.Tag t, HTMLDocument.HTMLReader.TagAction a)
+ {
+ tagToAction.put (t, a);
+ }
+
+ /**
+ * This is the last method called on the HTMLReader, allowing any pending
+ * changes to be flushed to the HTMLDocument.
+ */
+ public void flush() throws BadLocationException
+ {
+ flushImpl();
+ }
+
+ /**
+ * Flushes the buffer and handle partial inserts.
+ *
+ */
+ private void flushImpl()
+ throws BadLocationException
+ {
+ int oldLen = getLength();
+ int size = parseBuffer.size();
+ ElementSpec[] elems = new ElementSpec[size];
+ parseBuffer.copyInto(elems);
+ if (oldLen == 0)
+ create(elems);
+ else
+ insert(offset, elems);
+ parseBuffer.removeAllElements();
+ offset += getLength() - oldLen;
+ }
+
+ /**
+ * This method is called by the parser to indicate a block of
+ * text was encountered. Should insert the text appropriately.
+ *
+ * @param data the text that was inserted
+ * @param pos the position at which the text was inserted
+ */
+ public void handleText(char[] data, int pos)
+ {
+ if (shouldInsert() && data != null && data.length > 0)
+ {
+ if (inTextArea)
+ textAreaContent(data);
+ else if (inPreTag)
+ preContent(data);
+ else if (option != null)
+ option.setLabel(new String(data));
+ else if (inStyleTag)
+ {
+ if (styles == null)
+ styles = new ArrayList();
+ styles.add(new String(data));
+ }
+ else
+ addContent(data, 0, data.length);
+
+ }
+ }
+
+ /**
+ * Checks if the HTML tag should be inserted. The tags before insert tag (if
+ * specified) are not inserted. Also, the tags after the end of the html are
+ * not inserted.
+ *
+ * @return true if the tag should be inserted, false otherwise.
+ */
+ private boolean shouldInsert()
+ {
+ return ! endHTMLEncountered
+ && (insertTagEncountered || insertTag == null);
+ }
+
+ /**
+ * This method is called by the parser and should route the call to the
+ * proper handler for the tag.
+ *
+ * @param t the HTML.Tag
+ * @param a the attribute set
+ * @param pos the position at which the tag was encountered
+ */
+ public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos)
+ {
+ if (t == insertTag)
+ insertTagEncountered = true;
+
+ if (shouldInsert())
+ {
+ TagAction action = (TagAction) tagToAction.get(t);
+ if (action != null)
+ action.start(t, a);
+ }
+ }
+
+ /**
+ * This method called by parser to handle a comment block.
+ *
+ * @param data the comment
+ * @param pos the position at which the comment was encountered
+ */
+ public void handleComment(char[] data, int pos)
+ {
+ if (shouldInsert())
+ {
+ TagAction action = (TagAction) tagToAction.get(HTML.Tag.COMMENT);
+ if (action != null)
+ {
+ action.start(HTML.Tag.COMMENT, new SimpleAttributeSet());
+ action.end(HTML.Tag.COMMENT);
+ }
+ }
+ }
+
+ /**
+ * This method is called by the parser and should route the call to the
+ * proper handler for the tag.
+ *
+ * @param t the HTML.Tag
+ * @param pos the position at which the tag was encountered
+ */
+ public void handleEndTag(HTML.Tag t, int pos)
+ {
+ if (shouldInsert())
+ {
+ // If this is the </html> tag we need to stop calling the Actions
+ if (t == HTML.Tag.HTML)
+ endHTMLEncountered = true;
+
+ TagAction action = (TagAction) tagToAction.get(t);
+ if (action != null)
+ action.end(t);
+ }
+ }
+
+ /**
+ * This is a callback from the parser that should be routed to the
+ * appropriate handler for the tag.
+ *
+ * @param t the HTML.Tag that was encountered
+ * @param a the attribute set
+ * @param pos the position at which the tag was encountered
+ */
+ public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos)
+ {
+ if (t == insertTag)
+ insertTagEncountered = true;
+
+ if (shouldInsert())
+ {
+ TagAction action = (TagAction) tagToAction.get(t);
+ if (action != null)
+ {
+ action.start(t, a);
+ action.end(t);
+ }
+ }
+ }
+
+ /**
+ * This is invoked after the stream has been parsed but before it has been
+ * flushed.
+ *
+ * @param eol one of \n, \r, or \r\n, whichever was encountered the most in
+ * parsing the stream
+ * @since 1.3
+ */
+ public void handleEndOfLineString(String eol)
+ {
+ // FIXME: Implement.
+ }
+
+ /**
+ * Adds the given text to the textarea document. Called only when we are
+ * within a textarea.
+ *
+ * @param data the text to add to the textarea
+ */
+ protected void textAreaContent(char[] data)
+ {
+ try
+ {
+ int offset = textAreaDocument.getLength();
+ String text = new String(data);
+ textAreaDocument.setInitialText(text);
+ textAreaDocument.insertString(offset, text, null);
+ }
+ catch (BadLocationException ex)
+ {
+ // Must not happen as we insert at a model location that we
+ // got from the document itself.
+ assert false;
+ }
+ }
+
+ /**
+ * Adds the given text that was encountered in a <PRE> element.
+ * This adds synthesized lines to hold the text runs.
+ *
+ * @param data the text
+ */
+ protected void preContent(char[] data)
+ {
+ int start = 0;
+ for (int i = 0; i < data.length; i++)
+ {
+ if (data[i] == '\n')
+ {
+ addContent(data, start, i - start + 1);
+ blockClose(HTML.Tag.IMPLIED);
+ MutableAttributeSet atts = new SimpleAttributeSet();
+ atts.addAttribute(CSS.Attribute.WHITE_SPACE, "pre");
+ blockOpen(HTML.Tag.IMPLIED, atts);
+ start = i + 1;
+ }
+ }
+ if (start < data.length)
+ {
+ // Add remaining last line.
+ addContent(data, start, data.length - start);
+ }
+ }
+
+ /**
+ * Instructs the parse buffer to create a block element with the given
+ * attributes.
+ *
+ * @param t the tag that requires opening a new block
+ * @param attr the attribute set for the new block
+ */
+ protected void blockOpen(HTML.Tag t, MutableAttributeSet attr)
+ {
+ if (inImpliedParagraph())
+ blockClose(HTML.Tag.IMPLIED);
+
+ // Push the new tag on top of the stack.
+ parseStack.push(t);
+
+ DefaultStyledDocument.ElementSpec element;
+
+ AbstractDocument.AttributeContext ctx = getAttributeContext();
+ AttributeSet copy = attr.copyAttributes();
+ copy = ctx.addAttribute(copy, StyleConstants.NameAttribute, t);
+ element = new DefaultStyledDocument.ElementSpec(copy,
+ DefaultStyledDocument.ElementSpec.StartTagType);
+ parseBuffer.addElement(element);
+ }
+
+ /**
+ * Returns true when we are currently inside a paragraph, either
+ * a real one or an implied, false otherwise.
+ *
+ * @return
+ */
+ private boolean inParagraph()
+ {
+ boolean inParagraph = false;
+ if (! parseStack.isEmpty())
+ {
+ HTML.Tag top = parseStack.peek();
+ inParagraph = top == HTML.Tag.P || top == HTML.Tag.IMPLIED;
+ }
+ return inParagraph;
+ }
+
+ private boolean inImpliedParagraph()
+ {
+ boolean inParagraph = false;
+ if (! parseStack.isEmpty())
+ {
+ HTML.Tag top = parseStack.peek();
+ inParagraph = top == HTML.Tag.IMPLIED;
+ }
+ return inParagraph;
+ }
+
+ /**
+ * Instructs the parse buffer to close the block element associated with
+ * the given HTML.Tag
+ *
+ * @param t the HTML.Tag that is closing its block
+ */
+ protected void blockClose(HTML.Tag t)
+ {
+ DefaultStyledDocument.ElementSpec element;
+
+ if (inImpliedParagraph() && t != HTML.Tag.IMPLIED)
+ blockClose(HTML.Tag.IMPLIED);
+
+ // Pull the token from the stack.
+ if (! parseStack.isEmpty()) // Just to be sure.
+ parseStack.pop();
+
+ // If the previous tag is a start tag then we insert a synthetic
+ // content tag.
+ DefaultStyledDocument.ElementSpec prev;
+ prev = parseBuffer.size() > 0 ? (DefaultStyledDocument.ElementSpec)
+ parseBuffer.get(parseBuffer.size() - 1) : null;
+ if (prev != null &&
+ prev.getType() == DefaultStyledDocument.ElementSpec.StartTagType)
+ {
+ addContent(new char[]{' '}, 0, 1);
+ }
+
+ element = new DefaultStyledDocument.ElementSpec(null,
+ DefaultStyledDocument.ElementSpec.EndTagType);
+ parseBuffer.addElement(element);
+ }
+
+ /**
+ * Adds text to the appropriate context using the current character
+ * attribute set.
+ *
+ * @param data the text to add
+ * @param offs the offset at which to add it
+ * @param length the length of the text to add
+ */
+ protected void addContent(char[] data, int offs, int length)
+ {
+ addContent(data, offs, length, true);
+ }
+
+ /**
+ * Adds text to the appropriate context using the current character
+ * attribute set, and possibly generating an IMPLIED Tag if necessary.
+ *
+ * @param data the text to add
+ * @param offs the offset at which to add it
+ * @param length the length of the text to add
+ * @param generateImpliedPIfNecessary whether or not we should generate
+ * an HTML.Tag.IMPLIED tag if necessary
+ */
+ protected void addContent(char[] data, int offs, int length,
+ boolean generateImpliedPIfNecessary)
+ {
+ if (generateImpliedPIfNecessary && ! inParagraph())
+ {
+ blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet());
+ }
+
+ AbstractDocument.AttributeContext ctx = getAttributeContext();
+ DefaultStyledDocument.ElementSpec element;
+ AttributeSet attributes = null;
+
+ // Copy the attribute set, don't use the same object because
+ // it may change
+ if (charAttr != null)
+ attributes = charAttr.copyAttributes();
+ else
+ attributes = ctx.getEmptySet();
+ attributes = ctx.addAttribute(attributes, StyleConstants.NameAttribute,
+ HTML.Tag.CONTENT);
+ element = new DefaultStyledDocument.ElementSpec(attributes,
+ DefaultStyledDocument.ElementSpec.ContentType,
+ data, offs, length);
+
+ // Add the element to the buffer
+ parseBuffer.addElement(element);
+
+ if (parseBuffer.size() > threshold)
+ {
+ if (threshold <= MAX_THRESHOLD)
+ threshold *= GROW_THRESHOLD;
+ try
+ {
+ flushImpl();
+ }
+ catch (BadLocationException ble)
+ {
+ // TODO: what to do here?
+ }
+ }
+ }
+
+ /**
+ * Adds content that is specified in the attribute set.
+ *
+ * @param t the HTML.Tag
+ * @param a the attribute set specifying the special content
+ */
+ protected void addSpecialElement(HTML.Tag t, MutableAttributeSet a)
+ {
+ if (t != HTML.Tag.FRAME && ! inParagraph())
+ {
+ blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet());
+ }
+
+ a.addAttribute(StyleConstants.NameAttribute, t);
+
+ // The two spaces are required because some special elements like HR
+ // must be broken. At least two characters are needed to break into the
+ // two parts.
+ DefaultStyledDocument.ElementSpec spec =
+ new DefaultStyledDocument.ElementSpec(a.copyAttributes(),
+ DefaultStyledDocument.ElementSpec.ContentType,
+ new char[] {' '}, 0, 1 );
+ parseBuffer.add(spec);
+ }
+
+ }
+
+ /**
+ * Gets the reader for the parser to use when loading the document with HTML.
+ *
+ * @param pos - the starting position
+ * @return - the reader
+ */
+ public HTMLEditorKit.ParserCallback getReader(int pos)
+ {
+ return new HTMLReader(pos);
+ }
+
+ /**
+ * Gets the reader for the parser to use when loading the document with HTML.
+ *
+ * @param pos - the starting position
+ * @param popDepth - the number of EndTagTypes to generate before inserting
+ * @param pushDepth - the number of StartTagTypes with a direction
+ * of JoinNextDirection that should be generated before inserting,
+ * but after the end tags have been generated.
+ * @param insertTag - the first tag to start inserting into document
+ * @return - the reader
+ */
+ public HTMLEditorKit.ParserCallback getReader(int pos,
+ int popDepth,
+ int pushDepth,
+ HTML.Tag insertTag)
+ {
+ return new HTMLReader(pos, popDepth, pushDepth, insertTag);
+ }
+
+ /**
+ * Gets the reader for the parser to use when inserting the HTML fragment into
+ * the document. Checks if the parser is present, sets the parent in the
+ * element stack and removes any actions for BODY (it can be only one body in
+ * a HTMLDocument).
+ *
+ * @param pos - the starting position
+ * @param popDepth - the number of EndTagTypes to generate before inserting
+ * @param pushDepth - the number of StartTagTypes with a direction of
+ * JoinNextDirection that should be generated before inserting, but
+ * after the end tags have been generated.
+ * @param insertTag - the first tag to start inserting into document
+ * @param parent the element that will be the parent in the document. HTML
+ * parsing includes checks for the parent, so it must be available.
+ * @return - the reader
+ * @throws IllegalStateException if the parsert is not set.
+ */
+ public HTMLEditorKit.ParserCallback getInsertingReader(int pos, int popDepth,
+ int pushDepth,
+ HTML.Tag insertTag,
+ final Element parent)
+ throws IllegalStateException
+ {
+ if (parser == null)
+ throw new IllegalStateException("Parser has not been set");
+
+ HTMLReader reader = new HTMLReader(pos, popDepth, pushDepth, insertTag)
+ {
+ /**
+ * Ignore BODY.
+ */
+ public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos)
+ {
+ if (t != HTML.Tag.BODY)
+ super.handleStartTag(t, a, pos);
+ }
+
+ /**
+ * Ignore BODY.
+ */
+ public void handleEndTag(HTML.Tag t, int pos)
+ {
+ if (t != HTML.Tag.BODY)
+ super.handleEndTag(t, pos);
+ }
+ };
+
+ return reader;
+ }
+
+ /**
+ * Gets the child element that contains the attribute with the value or null.
+ * Not thread-safe.
+ *
+ * @param e - the element to begin search at
+ * @param attribute - the desired attribute
+ * @param value - the desired value
+ * @return the element found with the attribute and value specified or null if
+ * it is not found.
+ */
+ public Element getElement(Element e, Object attribute, Object value)
+ {
+ if (e != null)
+ {
+ if (e.getAttributes().containsAttribute(attribute, value))
+ return e;
+
+ int count = e.getElementCount();
+ for (int j = 0; j < count; j++)
+ {
+ Element child = e.getElement(j);
+ if (child.getAttributes().containsAttribute(attribute, value))
+ return child;
+
+ Element grandChild = getElement(child, attribute, value);
+ if (grandChild != null)
+ return grandChild;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the element that has the given id Attribute (for instance, &lt;p id
+ * ='my paragraph &gt;'). If it is not found, null is returned. The HTML tag,
+ * having this attribute, is not checked by this method and can be any. The
+ * method is not thread-safe.
+ *
+ * @param attrId - the value of the attribute id to look for
+ * @return the element that has the given id.
+ */
+ public Element getElement(String attrId)
+ {
+ return getElement(getDefaultRootElement(), HTML.Attribute.ID,
+ attrId);
+ }
+
+ /**
+ * Replaces the children of the given element with the contents of
+ * the string. The document must have an HTMLEditorKit.Parser set.
+ * This will be seen as at least two events, n inserts followed by a remove.
+ *
+ * @param elem - the brance element whose children will be replaced
+ * @param htmlText - the string to be parsed and assigned to element.
+ * @throws BadLocationException
+ * @throws IOException
+ * @throws IllegalArgumentException - if elem is a leaf
+ * @throws IllegalStateException - if an HTMLEditorKit.Parser has not been set
+ */
+ public void setInnerHTML(Element elem, String htmlText)
+ throws BadLocationException, IOException
+ {
+ if (elem.isLeaf())
+ throw new IllegalArgumentException("Element is a leaf");
+
+ int start = elem.getStartOffset();
+ int end = elem.getEndOffset();
+
+ HTMLEditorKit.ParserCallback reader = getInsertingReader(
+ end, 0, 0, HTML.Tag.BODY, elem);
+
+ // TODO charset
+ getParser().parse(new StringReader(htmlText), reader, true);
+
+ // Remove the previous content
+ remove(start, end - start);
+ }
+
+ /**
+ * Replaces the given element in the parent with the string. When replacing a
+ * leaf, this will attempt to make sure there is a newline present if one is
+ * needed. This may result in an additional element being inserted. This will
+ * be seen as at least two events, n inserts followed by a remove. The
+ * HTMLEditorKit.Parser must be set.
+ *
+ * @param elem - the branch element whose parent will be replaced
+ * @param htmlText - the string to be parsed and assigned to elem
+ * @throws BadLocationException
+ * @throws IOException
+ * @throws IllegalStateException - if parser is not set
+ */
+public void setOuterHTML(Element elem, String htmlText)
+ throws BadLocationException, IOException
+ {
+ // Remove the current element:
+ int start = elem.getStartOffset();
+ int end = elem.getEndOffset();
+
+ remove(start, end-start);
+
+ HTMLEditorKit.ParserCallback reader = getInsertingReader(
+ start, 0, 0, HTML.Tag.BODY, elem);
+
+ // TODO charset
+ getParser().parse(new StringReader(htmlText), reader, true);
+ }
+
+ /**
+ * Inserts the string before the start of the given element. The parser must
+ * be set.
+ *
+ * @param elem - the element to be the root for the new text.
+ * @param htmlText - the string to be parsed and assigned to elem
+ * @throws BadLocationException
+ * @throws IOException
+ * @throws IllegalStateException - if parser has not been set
+ */
+ public void insertBeforeStart(Element elem, String htmlText)
+ throws BadLocationException, IOException
+ {
+ HTMLEditorKit.ParserCallback reader = getInsertingReader(
+ elem.getStartOffset(), 0, 0, HTML.Tag.BODY, elem);
+
+ // TODO charset
+ getParser().parse(new StringReader(htmlText), reader, true);
+ }
+
+ /**
+ * Inserts the string at the end of the element. If elem's children are
+ * leaves, and the character at elem.getEndOffset() - 1 is a newline, then it
+ * will be inserted before the newline. The parser must be set.
+ *
+ * @param elem - the element to be the root for the new text
+ * @param htmlText - the text to insert
+ * @throws BadLocationException
+ * @throws IOException
+ * @throws IllegalStateException - if parser is not set
+ */
+ public void insertBeforeEnd(Element elem, String htmlText)
+ throws BadLocationException, IOException
+ {
+ HTMLEditorKit.ParserCallback reader = getInsertingReader(
+ elem.getEndOffset(), 0, 0, HTML.Tag.BODY, elem);
+
+ // TODO charset
+ getParser().parse(new StringReader(htmlText), reader, true);
+
+ }
+
+ /**
+ * Inserts the string after the end of the given element.
+ * The parser must be set.
+ *
+ * @param elem - the element to be the root for the new text
+ * @param htmlText - the text to insert
+ * @throws BadLocationException
+ * @throws IOException
+ * @throws IllegalStateException - if parser is not set
+ */
+ public void insertAfterEnd(Element elem, String htmlText)
+ throws BadLocationException, IOException
+ {
+ HTMLEditorKit.ParserCallback reader = getInsertingReader(
+ elem.getEndOffset(), 0, 0, HTML.Tag.BODY, elem);
+
+ // TODO charset
+ getParser().parse(new StringReader(htmlText), reader, true);
+ }
+
+ /**
+ * Inserts the string at the start of the element.
+ * The parser must be set.
+ *
+ * @param elem - the element to be the root for the new text
+ * @param htmlText - the text to insert
+ * @throws BadLocationException
+ * @throws IOException
+ * @throws IllegalStateException - if parser is not set
+ */
+ public void insertAfterStart(Element elem, String htmlText)
+ throws BadLocationException, IOException
+ {
+ HTMLEditorKit.ParserCallback reader = getInsertingReader(
+ elem.getStartOffset(), 0, 0, HTML.Tag.BODY, elem);
+
+ // TODO charset
+ getParser().parse(new StringReader(htmlText), reader, true);
+ }
+
+ /**
+ * Overridden to tag content with the synthetic HTML.Tag.CONTENT
+ * tag.
+ */
+ protected void insertUpdate(DefaultDocumentEvent evt, AttributeSet att)
+ {
+ if (att == null)
+ {
+ SimpleAttributeSet sas = new SimpleAttributeSet();
+ sas.addAttribute(StyleConstants.NameAttribute, HTML.Tag.CONTENT);
+ att = sas;
+ }
+ super.insertUpdate(evt, att);
+ }
+
+ /**
+ * Returns <code>true</code> when this document is inside a frame,
+ * <code>false</code> otherwise.
+ *
+ * @return <code>true</code> when this document is inside a frame,
+ * <code>false</code> otherwise
+ */
+ boolean isFrameDocument()
+ {
+ return frameDocument;
+ }
+
+ /**
+ * Set <code>true</code> when this document is inside a frame,
+ * <code>false</code> otherwise.
+ *
+ * @param frameDoc <code>true</code> when this document is inside a frame,
+ * <code>false</code> otherwise
+ */
+ void setFrameDocument(boolean frameDoc)
+ {
+ frameDocument = frameDoc;
+ }
+
+ /**
+ * Returns the target that is specified in the base tag, if this is the case.
+ *
+ * @return the target that is specified in the base tag, if this is the case
+ */
+ String getBaseTarget()
+ {
+ return baseTarget;
+ }
+
+ /**
+ * Updates the A tag's pseudo class value in response to a hyperlink
+ * action.
+ *
+ * @param el the corresponding element
+ * @param value the new value
+ */
+ void updateSpecialClass(Element el, HTML.Attribute cl, String value)
+ {
+ try
+ {
+ writeLock();
+ DefaultDocumentEvent ev =
+ new DefaultDocumentEvent(el.getStartOffset(), 1,
+ DocumentEvent.EventType.CHANGE);
+ AttributeSet elAtts = el.getAttributes();
+ AttributeSet anchorAtts = (AttributeSet) elAtts.getAttribute(HTML.Tag.A);
+ if (anchorAtts != null)
+ {
+ AttributeSet copy = elAtts.copyAttributes();
+ StyleSheet ss = getStyleSheet();
+ if (value != null)
+ {
+ anchorAtts = ss.addAttribute(anchorAtts, cl, value);
+ }
+ else
+ {
+ anchorAtts = ss.removeAttribute(anchorAtts, cl);
+ }
+ MutableAttributeSet matts = (MutableAttributeSet) elAtts;
+ ev.addEdit(new AttributeUndoableEdit(el, copy, false));
+ matts.removeAttribute(HTML.Tag.A);
+ matts.addAttribute(HTML.Tag.A, anchorAtts);
+ ev.end();
+ fireChangedUpdate(ev);
+ fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
+ }
+ }
+ finally
+ {
+ writeUnlock();
+ }
+ }
+
+}
diff --git a/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java
new file mode 100644
index 000000000..e3505d3c2
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java
@@ -0,0 +1,1520 @@
+/* HTMLEditorKit.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+import java.awt.Cursor;
+import java.awt.Point;
+
+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.io.Writer;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleContext;
+
+import javax.swing.Action;
+import javax.swing.JEditorPane;
+import javax.swing.SwingUtilities;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.EditorKit;
+import javax.swing.text.Element;
+import javax.swing.text.MutableAttributeSet;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.StyledDocument;
+import javax.swing.text.StyledEditorKit;
+import javax.swing.text.TextAction;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+import javax.swing.text.html.parser.ParserDelegator;
+
+/* Move these imports here after javax.swing.text.html to make it compile
+ with jikes. */
+import gnu.javax.swing.text.html.parser.GnuParserDelegator;
+import gnu.javax.swing.text.html.parser.HTML_401F;
+
+/**
+ * @author Lillian Angel (langel at redhat dot com)
+ */
+public class HTMLEditorKit
+ extends StyledEditorKit
+ implements Serializable, Cloneable, Accessible
+{
+
+ /**
+ * Fires the hyperlink events on the associated component
+ * when needed.
+ */
+ public static class LinkController
+ extends MouseAdapter
+ implements MouseMotionListener, Serializable
+ {
+
+ /**
+ * The element of the last anchor tag.
+ */
+ private Element lastAnchorElement;
+
+ /**
+ * Constructor
+ */
+ public LinkController()
+ {
+ super();
+ }
+
+ /**
+ * Dispatched when the mouse is clicked. If the component
+ * is read-only, then the clicked event is used to drive an
+ * attempt to follow the reference specified by a link
+ *
+ * @param e - the mouse event
+ */
+ public void mouseClicked(MouseEvent e)
+ {
+ JEditorPane editor = (JEditorPane) e.getSource();
+ if (! editor.isEditable() && SwingUtilities.isLeftMouseButton(e))
+ {
+ Point loc = e.getPoint();
+ int pos = editor.viewToModel(loc);
+ if (pos >= 0)
+ activateLink(pos, editor, e.getX(), e.getY());
+ }
+ }
+
+ /**
+ * Dispatched when the mouse is dragged on a component.
+ *
+ * @param e - the mouse event.
+ */
+ public void mouseDragged(MouseEvent e)
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Dispatched when the mouse cursor has moved into the component.
+ *
+ * @param e - the mouse event.
+ */
+ public void mouseMoved(MouseEvent e)
+ {
+ JEditorPane editor = (JEditorPane) e.getSource();
+ HTMLEditorKit kit = (HTMLEditorKit) editor.getEditorKit();
+ if (! editor.isEditable())
+ {
+ Document doc = editor.getDocument();
+ if (doc instanceof HTMLDocument)
+ {
+ Cursor newCursor = kit.getDefaultCursor();
+ HTMLDocument htmlDoc = (HTMLDocument) doc;
+ Point loc = e.getPoint();
+ int pos = editor.viewToModel(loc);
+ Element el = htmlDoc.getCharacterElement(pos);
+ if (pos < el.getStartOffset() || pos >= el.getEndOffset())
+ el = null;
+ if (el != null)
+ {
+ AttributeSet aAtts = (AttributeSet)
+ el.getAttributes().getAttribute(HTML.Tag.A);
+ if (aAtts != null)
+ {
+ if (el != lastAnchorElement)
+ {
+ if (lastAnchorElement != null)
+ htmlDoc.updateSpecialClass(lastAnchorElement,
+ HTML.Attribute.DYNAMIC_CLASS,
+ null);
+ lastAnchorElement = el;
+ htmlDoc.updateSpecialClass(el,
+ HTML.Attribute.DYNAMIC_CLASS,
+ "hover");
+ }
+ newCursor = kit.getLinkCursor();
+ }
+ else
+ {
+ if (lastAnchorElement != null)
+ htmlDoc.updateSpecialClass(lastAnchorElement,
+ HTML.Attribute.DYNAMIC_CLASS,
+ null);
+ lastAnchorElement = null;
+ }
+ }
+ else
+ {
+ if (lastAnchorElement != null)
+ htmlDoc.updateSpecialClass(lastAnchorElement,
+ HTML.Attribute.DYNAMIC_CLASS,
+ null);
+ lastAnchorElement = null;
+ }
+ if (editor.getCursor() != newCursor)
+ {
+ editor.setCursor(newCursor);
+ }
+ }
+ }
+ }
+
+ /**
+ * If the given position represents a link, then linkActivated is called
+ * on the JEditorPane.
+ *
+ * @param pos the position
+ * @param editor the editor pane
+ */
+ protected void activateLink(int pos, JEditorPane editor)
+ {
+ activateLink(pos, editor);
+ }
+
+ private void activateLink(int pos, JEditorPane editor, int x, int y)
+ {
+ // TODO: This is here for future extension for mapped links support.
+ // For the time beeing we implement simple hyperlinks.
+ Document doc = editor.getDocument();
+ if (doc instanceof HTMLDocument)
+ {
+ HTMLDocument htmlDoc = (HTMLDocument) doc;
+ Element el = htmlDoc.getCharacterElement(pos);
+ AttributeSet atts = el.getAttributes();
+ AttributeSet anchorAtts =
+ (AttributeSet) atts.getAttribute(HTML.Tag.A);
+ String href = null;
+ if (anchorAtts != null)
+ {
+ href = (String) anchorAtts.getAttribute(HTML.Attribute.HREF);
+ htmlDoc.updateSpecialClass(el, HTML.Attribute.PSEUDO_CLASS,
+ "visited");
+ }
+ else
+ {
+ // TODO: Implement link maps here.
+ }
+ HyperlinkEvent event = null;
+ if (href != null)
+ event = createHyperlinkEvent(editor, htmlDoc, href,
+ anchorAtts, el);
+ if (event != null)
+ editor.fireHyperlinkUpdate(event);
+ }
+
+ }
+
+ /**
+ * Creates a HyperlinkEvent for the specified href and anchor if
+ * possible. If for some reason this won't work, return null.
+ *
+ * @param editor the editor
+ * @param doc the document
+ * @param href the href link
+ * @param anchor the anchor
+ * @param el the element
+ *
+ * @return the hyperlink event, or <code>null</code> if we couldn't
+ * create one
+ */
+ private HyperlinkEvent createHyperlinkEvent(JEditorPane editor,
+ HTMLDocument doc,
+ String href,
+ AttributeSet anchor,
+ Element el)
+ {
+ URL url;
+ try
+ {
+ URL base = doc.getBase();
+ url = new URL(base, href);
+
+ }
+ catch (MalformedURLException ex)
+ {
+ url = null;
+ }
+ HyperlinkEvent ev;
+ if (doc.isFrameDocument())
+ {
+ String target = null;
+ if (anchor != null)
+ target = (String) anchor.getAttribute(HTML.Attribute.TARGET);
+ if (target == null || target.equals(""))
+ target = doc.getBaseTarget();
+ if (target == null || target.equals(""))
+ target = "_self";
+ ev = new HTMLFrameHyperlinkEvent(editor,
+ HyperlinkEvent.EventType.ACTIVATED,
+ url, href, el, target);
+ }
+ else
+ {
+ ev = new HyperlinkEvent(editor, HyperlinkEvent.EventType.ACTIVATED,
+ url, href, el);
+ }
+ return ev;
+ }
+ }
+
+ /**
+ * This class is used to insert a string of HTML into an existing
+ * document. At least 2 HTML.Tags need to be supplied. The first Tag (parentTag)
+ * identifies the parent in the document to add the elements to. The second, (addTag),
+ * identifies that the first tag should be added to the document as seen in the string.
+ * The parser will generate all appropriate (opening/closing tags_ even if they are not
+ * in the HTML string passed in.
+ */
+ public static class InsertHTMLTextAction
+ extends HTMLTextAction
+ {
+
+ /**
+ * Tag in HTML to start adding tags from.
+ */
+ protected HTML.Tag addTag;
+
+ /**
+ * Alternate tag in HTML to start adding tags from if parentTag is
+ * not found and alternateParentTag is not found.
+ */
+ protected HTML.Tag alternateAddTag;
+
+ /**
+ * Alternate tag to check if parentTag is not found.
+ */
+ protected HTML.Tag alternateParentTag;
+
+ /**
+ * HTML to insert.
+ */
+ protected String html;
+
+ /**
+ * Tag to check for in the document.
+ */
+ protected HTML.Tag parentTag;
+
+ /**
+ * Initializes all fields.
+ *
+ * @param name - the name of the document.
+ * @param html - the html to insert
+ * @param parentTag - the parent tag to check for
+ * @param addTag - the tag to start adding from
+ */
+ public InsertHTMLTextAction(String name, String html,
+ HTML.Tag parentTag, HTML.Tag addTag)
+ {
+ this(name, html, parentTag, addTag, null, null);
+ }
+
+ /**
+ * Initializes all fields and calls super
+ *
+ * @param name - the name of the document.
+ * @param html - the html to insert
+ * @param parentTag - the parent tag to check for
+ * @param addTag - the tag to start adding from
+ * @param alternateParentTag - the alternate parent tag
+ * @param alternateAddTag - the alternate add tag
+ */
+ public InsertHTMLTextAction(String name, String html, HTML.Tag parentTag,
+ HTML.Tag addTag, HTML.Tag alternateParentTag,
+ HTML.Tag alternateAddTag)
+ {
+ super(name);
+ // Fields are for easy access when the action is applied to an actual
+ // document.
+ this.html = html;
+ this.parentTag = parentTag;
+ this.addTag = addTag;
+ this.alternateParentTag = alternateParentTag;
+ this.alternateAddTag = alternateAddTag;
+ }
+
+ /**
+ * HTMLEditorKit.insertHTML is called. If an exception is
+ * thrown, it is wrapped in a RuntimeException and thrown.
+ *
+ * @param editor - the editor to use to get the editorkit
+ * @param doc -
+ * the Document to insert the HTML into.
+ * @param offset -
+ * where to begin inserting the HTML.
+ * @param html -
+ * the String to insert
+ * @param popDepth -
+ * the number of ElementSpec.EndTagTypes to generate before
+ * inserting
+ * @param pushDepth -
+ * the number of ElementSpec.StartTagTypes with a direction of
+ * ElementSpec.JoinNextDirection that should be generated before
+ * @param addTag -
+ * the first tag to start inserting into document
+ */
+ protected void insertHTML(JEditorPane editor, HTMLDocument doc, int offset,
+ String html, int popDepth, int pushDepth,
+ HTML.Tag addTag)
+ {
+ try
+ {
+ super.getHTMLEditorKit(editor).insertHTML(doc, offset, html,
+ popDepth, pushDepth, addTag);
+ }
+ catch (IOException e)
+ {
+ throw (RuntimeException) new RuntimeException("Parser is null.").initCause(e);
+ }
+ catch (BadLocationException ex)
+ {
+ throw (RuntimeException) new RuntimeException("BadLocationException: "
+ + offset).initCause(ex);
+ }
+ }
+
+ /**
+ * Invoked when inserting at a boundary. Determines the number of pops,
+ * and then the number of pushes that need to be performed. The it calls
+ * insertHTML.
+ *
+ * @param editor -
+ * the editor to use to get the editorkit
+ * @param doc -
+ * the Document to insert the HTML into.
+ * @param offset -
+ * where to begin inserting the HTML.
+ * @param insertElement -
+ * the element to insert
+ * @param html -
+ * the html to insert
+ * @param parentTag -
+ * the parent tag
+ * @param addTag -
+ * the first tag
+ */
+ protected void insertAtBoundary(JEditorPane editor,
+ HTMLDocument doc, int offset,
+ Element insertElement,
+ String html, HTML.Tag parentTag,
+ HTML.Tag addTag)
+ {
+ insertAtBoundry(editor, doc, offset, insertElement,
+ html, parentTag, addTag);
+ }
+
+ /**
+ * Invoked when inserting at a boundary. Determines the number of pops,
+ * and then the number of pushes that need to be performed. The it calls
+ * insertHTML.
+ *
+ * @param editor - the editor to use to get the editorkit
+ * @param doc -
+ * the Document to insert the HTML into.
+ * @param offset -
+ * where to begin inserting the HTML.
+ * @param insertElement - the element to insert
+ * @param html - the html to insert
+ * @param parentTag - the parent tag
+ * @param addTag - the first tag
+ *
+ * @deprecated as of v1.3, use insertAtBoundary
+ */
+ protected void insertAtBoundry(JEditorPane editor,
+ HTMLDocument doc,
+ int offset, Element insertElement,
+ String html, HTML.Tag parentTag,
+ HTML.Tag addTag)
+ {
+ Element parent = insertElement;
+ Element el;
+ // Find common parent element.
+ if (offset > 0 || insertElement == null)
+ {
+ el = doc.getDefaultRootElement();
+ while (el != null && el.getStartOffset() != offset
+ && ! el.isLeaf())
+ el = el.getElement(el.getElementIndex(offset));
+ parent = el != null ? el.getParentElement() : null;
+ }
+ if (parent != null)
+ {
+ int pops = 0;
+ int pushes = 0;
+ if (offset == 0 && insertElement != null)
+ {
+ el = parent;
+ while (el != null && ! el.isLeaf())
+ {
+ el = el.getElement(el.getElementIndex(offset));
+ pops++;
+ }
+ }
+ else
+ {
+ el = parent;
+ offset--;
+ while (el != null && ! el.isLeaf())
+ {
+ el = el.getElement(el.getElementIndex(offset));
+ pops++;
+ }
+ el = parent;
+ offset++;
+ while (el != null && el != insertElement)
+ {
+ el = el.getElement(el.getElementIndex(offset));
+ pushes++;
+ }
+ }
+ pops = Math.max(0, pops - 1);
+ insertHTML(editor, doc, offset, html, pops, pushes, addTag);
+ }
+ }
+
+ /**
+ * Inserts the HTML.
+ *
+ * @param ae - the action performed
+ */
+ public void actionPerformed(ActionEvent ae)
+ {
+ JEditorPane source = getEditor(ae);
+ if (source != null)
+ {
+ HTMLDocument d = getHTMLDocument(source);
+ int offset = source.getSelectionStart();
+ int length = d.getLength();
+ boolean inserted = true;
+ if (! tryInsert(source, d, offset, parentTag, addTag))
+ {
+ inserted = tryInsert(source, d, offset, alternateParentTag,
+ alternateAddTag);
+ }
+ if (inserted)
+ adjustSelection(source, d, offset, length);
+ }
+ }
+
+ /**
+ * Tries to insert the html chunk to the specified <code>addTag</code>.
+ *
+ * @param pane the editor
+ * @param doc the document
+ * @param offset the offset at which to insert
+ * @param tag the tag at which to insert
+ * @param addTag the add tag
+ *
+ * @return <code>true</code> when the html has been inserted successfully,
+ * <code>false</code> otherwise
+ */
+ private boolean tryInsert(JEditorPane pane, HTMLDocument doc, int offset,
+ HTML.Tag tag, HTML.Tag addTag)
+ {
+ boolean inserted = false;
+ Element el = findElementMatchingTag(doc, offset, tag);
+ if (el != null && el.getStartOffset() == offset)
+ {
+ insertAtBoundary(pane, doc, offset, el, html, tag, addTag);
+ inserted = true;
+ }
+ else if (offset > 0)
+ {
+ int depth = elementCountToTag(doc, offset - 1, tag);
+ if (depth != -1)
+ {
+ insertHTML(pane, doc, offset, html, depth, 0, addTag);
+ inserted = true;
+ }
+ }
+ return inserted;
+ }
+
+ /**
+ * Adjusts the selection after an insertion has been performed.
+ *
+ * @param pane the editor pane
+ * @param doc the document
+ * @param offset the insert offset
+ * @param oldLen the old document length
+ */
+ private void adjustSelection(JEditorPane pane, HTMLDocument doc,
+ int offset, int oldLen)
+ {
+ int newLen = doc.getLength();
+ if (newLen != oldLen && offset < newLen)
+ {
+ if (offset > 0)
+ {
+ String text;
+ try
+ {
+ text = doc.getText(offset - 1, 1);
+ }
+ catch (BadLocationException ex)
+ {
+ text = null;
+ }
+ if (text != null && text.length() > 0
+ && text.charAt(0) == '\n')
+ {
+ pane.select(offset, offset);
+ }
+ else
+ {
+ pane.select(offset + 1, offset + 1);
+ }
+ }
+ else
+ {
+ pane.select(1, 1);
+ }
+ }
+ }
+ }
+
+ /**
+ * Abstract Action class that helps inserting HTML into an existing document.
+ */
+ public abstract static class HTMLTextAction
+ extends StyledEditorKit.StyledTextAction
+ {
+
+ /**
+ * Constructor
+ */
+ public HTMLTextAction(String name)
+ {
+ super(name);
+ }
+
+ /**
+ * Gets the HTMLDocument from the JEditorPane.
+ *
+ * @param e - the editor pane
+ * @return the html document.
+ */
+ protected HTMLDocument getHTMLDocument(JEditorPane e)
+ {
+ Document d = e.getDocument();
+ if (d instanceof HTMLDocument)
+ return (HTMLDocument) d;
+ throw new IllegalArgumentException("Document is not a HTMLDocument.");
+ }
+
+ /**
+ * Gets the HTMLEditorKit
+ *
+ * @param e - the JEditorPane to get the HTMLEditorKit from.
+ * @return the HTMLEditorKit
+ */
+ protected HTMLEditorKit getHTMLEditorKit(JEditorPane e)
+ {
+ EditorKit d = e.getEditorKit();
+ if (d instanceof HTMLEditorKit)
+ return (HTMLEditorKit) d;
+ throw new IllegalArgumentException("EditorKit is not a HTMLEditorKit.");
+ }
+
+ /**
+ * Returns an array of Elements that contain the offset.
+ * The first elements corresponds to the roots of the doc.
+ *
+ * @param doc - the document to get the Elements from.
+ * @param offset - the offset the Elements must contain
+ * @return an array of all the elements containing the offset.
+ */
+ protected Element[] getElementsAt(HTMLDocument doc,
+ int offset)
+ {
+ return getElementsAt(doc.getDefaultRootElement(), offset, 0);
+ }
+
+ /**
+ * Helper function to get all elements using recursion.
+ */
+ private Element[] getElementsAt(Element root, int offset, int depth)
+ {
+ Element[] elements = null;
+ if (root != null)
+ {
+ if (root.isLeaf())
+ {
+ elements = new Element[depth + 1];
+ elements[depth] = root;
+ return elements;
+ }
+ elements = getElementsAt(root.getElement(root.getElementIndex(offset)),
+ offset, depth + 1);
+ elements[depth] = root;
+ }
+ return elements;
+ }
+
+ /**
+ * Returns the number of elements, starting at the deepest point, needed
+ * to get an element representing tag. -1 if no elements are found, 0 if
+ * the parent of the leaf at offset represents the tag.
+ *
+ * @param doc -
+ * the document to search
+ * @param offset -
+ * the offset to check
+ * @param tag -
+ * the tag to look for
+ * @return - the number of elements needed to get an element representing
+ * tag.
+ */
+ protected int elementCountToTag(HTMLDocument doc,
+ int offset, HTML.Tag tag)
+ {
+ Element root = doc.getDefaultRootElement();
+ int num = -1;
+ Element next = root.getElement(root.getElementIndex(offset));
+
+ while (!next.isLeaf())
+ {
+ num++;
+ if (next.getAttributes().
+ getAttribute(StyleConstants.NameAttribute).equals(tag))
+ return num;
+ next = next.getElement(next.getElementIndex(offset));
+ }
+ return num;
+ }
+
+ /**
+ * Gets the deepest element at offset with the
+ * matching tag.
+ *
+ * @param doc - the document to search
+ * @param offset - the offset to check for
+ * @param tag - the tag to match
+ * @return - the element that is found, null if not found.
+ */
+ protected Element findElementMatchingTag(HTMLDocument doc,
+ int offset, HTML.Tag tag)
+ {
+ Element element = doc.getDefaultRootElement();
+ Element tagElement = null;
+
+ while (element != null)
+ {
+ Object otag = element.getAttributes().getAttribute(
+ StyleConstants.NameAttribute);
+ if (otag instanceof HTML.Tag && otag.equals(tag))
+ tagElement = element;
+ element = element.getElement(element.getElementIndex(offset));
+ }
+
+ return tagElement;
+ }
+ }
+
+ /**
+ * A {@link ViewFactory} that is able to create {@link View}s for
+ * the <code>Element</code>s that are supported.
+ */
+ public static class HTMLFactory
+ implements ViewFactory
+ {
+
+ /**
+ * Constructor
+ */
+ public HTMLFactory()
+ {
+ // Do Nothing here.
+ }
+
+ /**
+ * Creates a {@link View} for the specified <code>Element</code>.
+ *
+ * @param element the <code>Element</code> to create a <code>View</code>
+ * for
+ * @return the <code>View</code> for the specified <code>Element</code>
+ * or <code>null</code> if the type of <code>element</code> is
+ * not supported
+ */
+ public View create(Element element)
+ {
+ View view = null;
+ Object attr =
+ element.getAttributes().getAttribute(StyleConstants.NameAttribute);
+ if (attr instanceof HTML.Tag)
+ {
+ HTML.Tag tag = (HTML.Tag) attr;
+
+ if (tag == HTML.Tag.IMPLIED || tag == HTML.Tag.P
+ || tag == HTML.Tag.H1 || tag == HTML.Tag.H2
+ || tag == HTML.Tag.H3 || tag == HTML.Tag.H4
+ || tag == HTML.Tag.H5 || tag == HTML.Tag.H6
+ || tag == HTML.Tag.DT)
+ view = new ParagraphView(element);
+ else if (tag == HTML.Tag.LI || tag == HTML.Tag.DL
+ || tag == HTML.Tag.DD || tag == HTML.Tag.BODY
+ || tag == HTML.Tag.HTML || tag == HTML.Tag.CENTER
+ || tag == HTML.Tag.DIV
+ || tag == HTML.Tag.BLOCKQUOTE
+ || tag == HTML.Tag.PRE
+ || tag == HTML.Tag.FORM
+ // Misplaced TD and TH tags get mapped as vertical block.
+ // Note that correctly placed tags get mapped in TableView.
+ || tag == HTML.Tag.TD || tag == HTML.Tag.TH)
+ view = new BlockView(element, View.Y_AXIS);
+ else if (tag == HTML.Tag.TR)
+ // Misplaced TR tags get mapped as horizontal blocks.
+ // Note that correctly placed tags get mapped in TableView.
+ view = new BlockView(element, View.X_AXIS);
+ else if (tag == HTML.Tag.IMG)
+ view = new ImageView(element);
+
+ else if (tag == HTML.Tag.CONTENT)
+ view = new InlineView(element);
+ else if (tag == HTML.Tag.HEAD)
+ view = new NullView(element);
+ else if (tag == HTML.Tag.TABLE)
+ view = new javax.swing.text.html.TableView(element);
+ else if (tag == HTML.Tag.HR)
+ view = new HRuleView(element);
+ else if (tag == HTML.Tag.BR)
+ view = new BRView(element);
+ else if (tag == HTML.Tag.INPUT || tag == HTML.Tag.SELECT
+ || tag == HTML.Tag.TEXTAREA)
+ view = new FormView(element);
+
+ else if (tag == HTML.Tag.MENU || tag == HTML.Tag.DIR
+ || tag == HTML.Tag.UL || tag == HTML.Tag.OL)
+ view = new ListView(element);
+ else if (tag == HTML.Tag.FRAMESET)
+ view = new FrameSetView(element);
+ else if (tag == HTML.Tag.FRAME)
+ view = new FrameView(element);
+ else if (tag == HTML.Tag.OBJECT)
+ view = new ObjectView(element);
+ }
+ if (view == null)
+ {
+ view = new NullView(element);
+ }
+ return view;
+ }
+ }
+
+ /**
+ * The abstract HTML parser declaration.
+ */
+ public abstract static class Parser
+ {
+ /**
+ * Parse the HTML text, calling various methods of the provided callback
+ * in response to the occurence of the corresponding HTML constructions.
+ * @param reader The reader to read the source HTML from.
+ * @param callback The callback to receive information about the parsed
+ * HTML structures
+ * @param ignoreCharSet If true, the parser ignores all charset information
+ * that may be present in HTML documents.
+ * @throws IOException, normally if the reader throws one.
+ */
+ public abstract void parse(Reader reader, ParserCallback callback,
+ boolean ignoreCharSet) throws IOException;
+ }
+
+ /**
+ * The "hook" that receives all information about the HTML document
+ * structure while parsing it. The methods are invoked by parser
+ * and should be normally overridden.
+ */
+ public static class ParserCallback
+ {
+ /**
+ * If the tag does not occurs in the html stream directly, but
+ * is supposed by parser, the tag attribute set contains this additional
+ * attribute, having value Boolean.True.
+ */
+ public static final Object IMPLIED = "_implied_";
+
+ /**
+ * Constructor
+ */
+ public ParserCallback()
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * The parser calls this method after it finishes parsing the document.
+ */
+ public void flush() throws BadLocationException
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Handle HTML comment, present in the given position.
+ * @param comment the comment
+ * @position the position of the comment in the text being parsed.
+ */
+ public void handleComment(char[] comment, int position)
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Notifies about the character sequences, used to separate lines in
+ * this document. The parser calls this method after it finishes
+ * parsing the document, but before flush().
+ * @param end_of_line The "end of line sequence", one of: \r or \n or \r\n.
+ */
+ public void handleEndOfLineString(String end_of_line)
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * The method is called when the HTML closing tag ((like &lt;/table&gt;)
+ * is found or if the parser concludes that the one should be present
+ * in the current position.
+ * @param tag The tag being handled
+ * @param position the tag position in the text being parsed.
+ */
+ public void handleEndTag(HTML.Tag tag, int position)
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Handle the error.
+ * @param message The message, explaining the error.
+ * @param position The starting position of the fragment that has caused
+ * the error in the html document being parsed.
+ */
+ public void handleError(String message, int position)
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Handle the tag with no content, like &lt;br&gt;. The method is
+ * called for the elements that, in accordance with the current DTD,
+ * has an empty content.
+ * @param tag The tag being handled.
+ * @param position The tag position in the text being parsed.
+ */
+ public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet attributes,
+ int position)
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * The method is called when the HTML opening tag ((like &lt;table&gt;)
+ * is found or if the parser concludes that the one should be present
+ * in the current position.
+ * @param tag The tag being handled
+ * @param position The tag position in the text being parsed
+ */
+ public void handleStartTag(HTML.Tag tag, MutableAttributeSet attributes,
+ int position)
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Handle the text section.
+ * @param text A section text.
+ * @param position The text position in the HTML document text being parsed.
+ */
+ public void handleText(char[] text, int position)
+ {
+ // Nothing to do here.
+ }
+ }
+
+ /**
+ * Use serialVersionUID (v1.4) for interoperability.
+ */
+ private static final long serialVersionUID = 8751997116710384592L;
+
+ /**
+ * Default cascading stylesheed file ("default.css").
+ */
+ public static final String DEFAULT_CSS = "default.css";
+
+ /**
+ * The <b>bold</b> action identifier.
+ */
+ public static final String BOLD_ACTION = "html-bold-action";
+
+ /**
+ * The <i>italic</i> action identifier.
+ */
+ public static final String ITALIC_ACTION = "html-italic-action";
+
+ /**
+ * The <font color="#FF0000">color</font> action indentifier
+ * (passing the color as an argument).
+ */
+ public static final String COLOR_ACTION = "html-color-action";
+
+ /**
+ * The <font size="+1">increase</font> font action identifier.
+ */
+ public static final String FONT_CHANGE_BIGGER = "html-font-bigger";
+
+ /**
+ * The <font size="-1">decrease</font> font action identifier.
+ */
+ public static final String FONT_CHANGE_SMALLER = "html-font-smaller";
+
+ /**
+ * Align images at the bottom.
+ */
+ public static final String IMG_ALIGN_BOTTOM = "html-image-align-bottom";
+
+ /**
+ * Align images at the middle.
+ */
+ public static final String IMG_ALIGN_MIDDLE = "html-image-align-middle";
+
+ /**
+ * Align images at the top.
+ */
+ public static final String IMG_ALIGN_TOP = "html-image-align-top";
+
+ /**
+ * Align images at the border.
+ */
+ public static final String IMG_BORDER = "html-image-border";
+
+ /**
+ * The "logical style" action identifier, passing that style as parameter.
+ */
+ public static final String LOGICAL_STYLE_ACTION = "html-logical-style-action";
+
+ /**
+ * The "ident paragraph left" action.
+ */
+ public static final String PARA_INDENT_LEFT = "html-para-indent-left";
+
+ /**
+ * The "ident paragraph right" action.
+ */
+ public static final String PARA_INDENT_RIGHT = "html-para-indent-right";
+
+ /**
+ * Actions for HTML
+ */
+ private static final Action[] defaultActions =
+ {
+ new InsertHTMLTextAction("InsertTable",
+ "<table border=1><tr><td></td></tr></table>",
+ HTML.Tag.BODY, HTML.Tag.TABLE),
+ new InsertHTMLTextAction("InsertTableRow",
+ "<table border=1><tr><td></td></tr></table>",
+ HTML.Tag.TABLE, HTML.Tag.TR,
+ HTML.Tag.BODY, HTML.Tag.TABLE),
+ new InsertHTMLTextAction("InsertTableCell",
+ "<table border=1><tr><td></td></tr></table>",
+ HTML.Tag.TR, HTML.Tag.TD,
+ HTML.Tag.BODY, HTML.Tag.TABLE),
+ new InsertHTMLTextAction("InsertUnorderedList",
+ "<ul><li></li></ul>",
+ HTML.Tag.BODY, HTML.Tag.UL),
+ new InsertHTMLTextAction("InsertUnorderedListItem",
+ "<ul><li></li></ul>",
+ HTML.Tag.UL, HTML.Tag.LI,
+ HTML.Tag.BODY, HTML.Tag.UL),
+ new InsertHTMLTextAction("InsertOrderedList",
+ "<ol><li></li></ol>",
+ HTML.Tag.BODY, HTML.Tag.OL),
+ new InsertHTMLTextAction("InsertOrderedListItem",
+ "<ol><li></li></ol>",
+ HTML.Tag.OL, HTML.Tag.LI,
+ HTML.Tag.BODY, HTML.Tag.OL),
+ new InsertHTMLTextAction("InsertPre",
+ "<pre></pre>", HTML.Tag.BODY, HTML.Tag.PRE)
+ // TODO: The reference impl has an InsertHRAction too.
+ };
+
+ /**
+ * The current style sheet.
+ */
+ private StyleSheet styleSheet;
+
+ /**
+ * The ViewFactory for HTMLFactory.
+ */
+ HTMLFactory viewFactory;
+
+ /**
+ * The Cursor for links.
+ */
+ Cursor linkCursor;
+
+ /**
+ * The default cursor.
+ */
+ Cursor defaultCursor;
+
+ /**
+ * The parser.
+ */
+ Parser parser;
+
+ /**
+ * The mouse listener used for links.
+ */
+ private LinkController linkController;
+
+ /** The content type */
+ String contentType = "text/html";
+
+ /** The input attributes defined by default.css */
+ MutableAttributeSet inputAttributes;
+
+ /** The editor pane used. */
+ JEditorPane editorPane;
+
+ /**
+ * Whether or not the editor kit handles form submissions.
+ *
+ * @see #isAutoFormSubmission()
+ * @see #setAutoFormSubmission(boolean)
+ */
+ private boolean autoFormSubmission;
+
+ /**
+ * Constructs an HTMLEditorKit, creates a StyleContext, and loads the style sheet.
+ */
+ public HTMLEditorKit()
+ {
+ linkController = new LinkController();
+ autoFormSubmission = true;
+ }
+
+ /**
+ * Gets a factory suitable for producing views of any
+ * models that are produced by this kit.
+ *
+ * @return the view factory suitable for producing views.
+ */
+ public ViewFactory getViewFactory()
+ {
+ if (viewFactory == null)
+ viewFactory = new HTMLFactory();
+ return viewFactory;
+ }
+
+ /**
+ * Create a text storage model for this type of editor.
+ *
+ * @return the model
+ */
+ public Document createDefaultDocument()
+ {
+ // Protect the shared stylesheet.
+ StyleSheet styleSheet = getStyleSheet();
+ StyleSheet ss = new StyleSheet();
+ ss.addStyleSheet(styleSheet);
+
+ HTMLDocument document = new HTMLDocument(ss);
+ document.setParser(getParser());
+ document.setAsynchronousLoadPriority(4);
+ document.setTokenThreshold(100);
+ return document;
+ }
+
+ /**
+ * Get the parser that this editor kit uses for reading HTML streams. This
+ * method can be overridden to use the alternative parser.
+ *
+ * @return the HTML parser (by default, {@link ParserDelegator}).
+ */
+ protected Parser getParser()
+ {
+ if (parser == null)
+ {
+ parser = new GnuParserDelegator(HTML_401F.getInstance());
+ }
+ return parser;
+ }
+
+ /**
+ * Inserts HTML into an existing document.
+ *
+ * @param doc - the Document to insert the HTML into.
+ * @param offset - where to begin inserting the HTML.
+ * @param html - the String to insert
+ * @param popDepth - the number of ElementSpec.EndTagTypes
+ * to generate before inserting
+ * @param pushDepth - the number of ElementSpec.StartTagTypes
+ * with a direction of ElementSpec.JoinNextDirection that
+ * should be generated before
+ * @param insertTag - the first tag to start inserting into document
+ * @throws IOException - on any I/O error
+ * @throws BadLocationException - if pos represents an invalid location
+ * within the document
+ */
+ public void insertHTML(HTMLDocument doc, int offset, String html,
+ int popDepth, int pushDepth, HTML.Tag insertTag)
+ throws BadLocationException, IOException
+ {
+ Parser parser = getParser();
+ if (offset < 0 || offset > doc.getLength())
+ throw new BadLocationException("Bad location", offset);
+ if (parser == null)
+ throw new IOException("Parser is null.");
+
+ ParserCallback pc = doc.getReader(offset, popDepth, pushDepth, insertTag);
+
+ // FIXME: What should ignoreCharSet be set to?
+
+ // parser.parse inserts html into the buffer
+ parser.parse(new StringReader(html), pc, false);
+ pc.flush();
+ }
+
+ /**
+ * Inserts content from the given stream. Inserting HTML into a non-empty
+ * document must be inside the body Element, if you do not insert into
+ * the body an exception will be thrown. When inserting into a non-empty
+ * document all tags outside of the body (head, title) will be dropped.
+ *
+ * @param in - the stream to read from
+ * @param doc - the destination for the insertion
+ * @param pos - the location in the document to place the content
+ * @throws IOException - on any I/O error
+ * @throws BadLocationException - if pos represents an invalid location
+ * within the document
+ */
+ public void read(Reader in, Document doc, int pos) throws IOException,
+ BadLocationException
+ {
+ if (doc instanceof HTMLDocument)
+ {
+ Parser parser = getParser();
+ if (pos < 0 || pos > doc.getLength())
+ throw new BadLocationException("Bad location", pos);
+ if (parser == null)
+ throw new IOException("Parser is null.");
+
+ HTMLDocument hd = ((HTMLDocument) doc);
+ if (editorPane != null)
+ hd.setBase(editorPane.getPage());
+ ParserCallback pc = hd.getReader(pos);
+
+ // FIXME: What should ignoreCharSet be set to?
+
+ // parser.parse inserts html into the buffer
+ parser.parse(in, pc, false);
+ pc.flush();
+ }
+ else
+ // read in DefaultEditorKit is called.
+ // the string is inserted in the document as usual.
+ super.read(in, doc, pos);
+ }
+
+ /**
+ * Writes content from a document to the given stream in
+ * an appropriate format.
+ *
+ * @param out - the stream to write to
+ * @param doc - the source for the write
+ * @param pos - the location in the document to get the content.
+ * @param len - the amount to write out
+ * @throws IOException - on any I/O error
+ * @throws BadLocationException - if pos represents an invalid location
+ * within the document
+ */
+ public void write(Writer out, Document doc, int pos, int len)
+ throws IOException, BadLocationException
+ {
+ if (doc instanceof HTMLDocument)
+ {
+ HTMLWriter writer = new HTMLWriter(out, (HTMLDocument) doc, pos, len);
+ writer.write();
+ }
+ else if (doc instanceof StyledDocument)
+ {
+ MinimalHTMLWriter writer = new MinimalHTMLWriter(out,
+ (StyledDocument) doc,
+ pos, len);
+ writer.write();
+ }
+ else
+ super.write(out, doc, pos, len);
+ }
+
+ /**
+ * Gets the content type that the kit supports.
+ * This kit supports the type text/html.
+ *
+ * @returns the content type supported.
+ */
+ public String getContentType()
+ {
+ return contentType;
+ }
+
+ /**
+ * Creates a copy of the editor kit.
+ *
+ * @return a copy of this.
+ */
+ public Object clone()
+ {
+ // FIXME: Need to clone all fields
+ HTMLEditorKit copy = (HTMLEditorKit) super.clone();
+ copy.linkController = new LinkController();
+ return copy;
+ }
+
+ /**
+ * Copies the key/values in elements AttributeSet into set.
+ * This does not copy component, icon, or element names attributes.
+ * This is called anytime the caret moves over a different location.
+ *
+ * @param element - the element to create the input attributes for.
+ * @param set - the set to copy the values into.
+ */
+ protected void createInputAttributes(Element element,
+ MutableAttributeSet set)
+ {
+ set.removeAttributes(set);
+ set.addAttributes(element.getAttributes());
+ // FIXME: Not fully implemented.
+ }
+
+ /**
+ * Called when this is installed into the JEditorPane.
+ *
+ * @param c - the JEditorPane installed into.
+ */
+ public void install(JEditorPane c)
+ {
+ super.install(c);
+ c.addMouseListener(linkController);
+ c.addMouseMotionListener(linkController);
+ editorPane = c;
+ }
+
+ /**
+ * Called when the this is removed from the JEditorPane.
+ * It unregisters any listeners.
+ *
+ * @param c - the JEditorPane being removed from.
+ */
+ public void deinstall(JEditorPane c)
+ {
+ super.deinstall(c);
+ c.removeMouseListener(linkController);
+ c.removeMouseMotionListener(linkController);
+ editorPane = null;
+ }
+
+ /**
+ * Gets the AccessibleContext associated with this.
+ *
+ * @return the AccessibleContext for this.
+ */
+ public AccessibleContext getAccessibleContext()
+ {
+ // FIXME: Should return an instance of
+ // javax.swing.text.html.AccessibleHTML$RootHTMLAccessibleContext
+ // Not implemented yet.
+ return null;
+ }
+
+ /**
+ * Gets the action list. This list is supported by the superclass
+ * augmented by the collection of actions defined locally for style
+ * operations.
+ *
+ * @return an array of all the actions
+ */
+ public Action[] getActions()
+ {
+ return TextAction.augmentList(super.getActions(), defaultActions);
+ }
+
+ /**
+ * Returns the default cursor.
+ *
+ * @return the default cursor
+ */
+ public Cursor getDefaultCursor()
+ {
+ if (defaultCursor == null)
+ defaultCursor = Cursor.getDefaultCursor();
+ return defaultCursor;
+ }
+
+ /**
+ * Returns the cursor for links.
+ *
+ * @return the cursor for links.
+ */
+ public Cursor getLinkCursor()
+ {
+ if (linkCursor == null)
+ linkCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
+ return linkCursor;
+ }
+
+ /**
+ * Sets the Cursor for links.
+ *
+ * @param cursor - the new cursor for links.
+ */
+ public void setLinkCursor(Cursor cursor)
+ {
+ linkCursor = cursor;
+ }
+
+ /**
+ * Sets the default cursor.
+ *
+ * @param cursor - the new default cursor.
+ */
+ public void setDefaultCursor(Cursor cursor)
+ {
+ defaultCursor = cursor;
+ }
+
+ /**
+ * Gets the input attributes used for the styled editing actions.
+ *
+ * @return the attribute set
+ */
+ public MutableAttributeSet getInputAttributes()
+ {
+ return inputAttributes;
+ }
+
+ /**
+ * Get the set of styles currently being used to render the HTML elements.
+ * By default the resource specified by DEFAULT_CSS gets loaded, and is
+ * shared by all HTMLEditorKit instances.
+ *
+ * @return the style sheet.
+ */
+ public StyleSheet getStyleSheet()
+ {
+ if (styleSheet == null)
+ {
+ try
+ {
+ styleSheet = new StyleSheet();
+ Class<?> c = HTMLEditorKit.class;
+ InputStream in = c.getResourceAsStream(DEFAULT_CSS);
+ InputStreamReader r = new InputStreamReader(in);
+ styleSheet.loadRules(r, null);
+ r.close();
+ }
+ catch (IOException ex)
+ {
+ throw new RuntimeException("No style available.", ex);
+ }
+ }
+ return styleSheet;
+ }
+
+ /**
+ * Set the set of styles to be used to render the various HTML elements.
+ * These styles are specified in terms of CSS specifications. Each document
+ * produced by the kit will have a copy of the sheet which it can add the
+ * document specific styles to. By default, the StyleSheet specified is shared
+ * by all HTMLEditorKit instances.
+ *
+ * @param s - the new style sheet
+ */
+ public void setStyleSheet(StyleSheet s)
+ {
+ styleSheet = s;
+ }
+
+ /**
+ * Returns <code>true</code> when forms should be automatically submitted
+ * by the editor kit. Set this to <code>false</code> when you want to
+ * intercept form submission. In this case you'd want to listen for
+ * hyperlink events on the document and handle FormSubmitEvents specially.
+ *
+ * The default is <code>true</code>.
+ *
+ * @return <code>true</code> when forms should be automatically submitted
+ * by the editor kit, <code>false</code> otherwise
+ *
+ * @since 1.5
+ *
+ * @see #setAutoFormSubmission(boolean)
+ * @see FormSubmitEvent
+ */
+ public boolean isAutoFormSubmission()
+ {
+ return autoFormSubmission;
+ }
+
+ /**
+ * Sets whether or not the editor kit should automatically submit forms.
+ *
+ * @param auto <code>true</code> when the editor kit should handle form
+ * submission, <code>false</code> otherwise
+ *
+ * @since 1.5
+ *
+ * @see #isAutoFormSubmission()
+ */
+ public void setAutoFormSubmission(boolean auto)
+ {
+ autoFormSubmission = auto;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/HTMLFrameHyperlinkEvent.java b/libjava/classpath/javax/swing/text/html/HTMLFrameHyperlinkEvent.java
new file mode 100644
index 000000000..e146965d7
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/HTMLFrameHyperlinkEvent.java
@@ -0,0 +1,130 @@
+/* HTMLFrameHyperlinkEvent.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import java.net.URL;
+
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.text.Element;
+
+/**
+ * HTMLFrameHyperlinkEvent transfers information about the link that was
+ * activated in a frame.
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class HTMLFrameHyperlinkEvent extends HyperlinkEvent
+{
+ private final String target_frame;
+
+ /**
+ * Creates a new hypertext link event.
+ *
+ * @param source The object this link is associated to.
+ * @param type The type of event.
+ * @param url The URL this link pointing too.
+ * @param element The element in the document representing the anchor.
+ * @param frame - the Frame to display the document in.
+ */
+ public HTMLFrameHyperlinkEvent(Object source, EventType type, URL url,
+ Element element, String frame)
+ {
+ super(source, type, url, frame, element);
+ target_frame = frame;
+ }
+
+ /**
+ * Creates a new hypertext link event.
+ *
+ * @param source The object this link is associated to.
+ * @param type The type of event.
+ * @param url The URL this link pointing too.
+ * @param frame - the Frame to display the document in.
+ */
+ public HTMLFrameHyperlinkEvent(Object source, EventType type, URL url,
+ String frame)
+ {
+ super(source, type, url, frame);
+ target_frame = frame;
+ }
+
+ /**
+ * Creates a new hypertext link event.
+ *
+ * @param source The object this link is associated to.
+ * @param type The type of event.
+ * @param url The URL this link pointing too.
+ * @param description The description for this link.
+ * @param element The element in the document representing the anchor.
+ * @param frame - the Frame to display the document in.
+ */
+ public HTMLFrameHyperlinkEvent(Object source, EventType type, URL url,
+ String description, Element element,
+ String frame)
+ {
+ super(source, type, url, description, element);
+ target_frame = frame;
+ }
+
+ /**
+ * Creates a new hypertext link event.
+ *
+ * @param source The object this link is associated to.
+ * @param type The type of event.
+ * @param url The URL this link pointing too.
+ * @param description The description for this link.
+ * @param frame - the Frame to display the document in.
+ */
+ public HTMLFrameHyperlinkEvent(Object source, EventType type, URL url,
+ String description, String frame)
+ {
+ super(source, type, url, description);
+ target_frame = frame;
+ }
+
+ /**
+ * Gets the string, passed as the target frame identifier.
+ *
+ * @return the target for the link.
+ */
+ public String getTarget()
+ {
+ return target_frame;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/HTMLWriter.java b/libjava/classpath/javax/swing/text/html/HTMLWriter.java
new file mode 100644
index 000000000..55d25ccbb
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/HTMLWriter.java
@@ -0,0 +1,1088 @@
+/* HTMLWriter.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import java.util.Enumeration;
+import java.util.HashSet;
+
+import javax.swing.ComboBoxModel;
+
+import javax.swing.text.AbstractWriter;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.StyleConstants;
+
+import javax.swing.text.html.HTML;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.Option;
+
+/**
+ * HTMLWriter,
+ * A Writer for HTMLDocuments.
+ *
+ * @author David Fu (fchoong at netbeans.jp)
+ */
+
+public class HTMLWriter
+ extends AbstractWriter
+{
+ /**
+ * We keep a reference of the writer passed by the construct.
+ */
+ private Writer outWriter = null;
+
+ /**
+ * We keep a reference of the HTMLDocument passed by the construct.
+ */
+ private HTMLDocument htmlDoc = null;
+
+ /**
+ * Used to keep track of which embedded has been written out.
+ */
+ private HashSet<HTML.Tag> openEmbeddedTagHashSet = null;
+
+ private String new_line_str = "" + NEWLINE;
+
+ private char[] html_entity_char_arr = {'<', '>', '&', '"'};
+
+ private String[] html_entity_escape_str_arr = {"&lt;", "&gt;", "&amp;",
+ "&quot;"};
+
+ // variables used to output Html Fragment
+ private int doc_pos = -1;
+ private int doc_len = -1;
+ private int doc_offset_remaining = -1;
+ private int doc_len_remaining = -1;
+ private HashSet<Element> htmlFragmentParentHashSet = null;
+ private Element startElem = null;
+ private Element endElem = null;
+ private boolean fg_pass_start_elem = false;
+ private boolean fg_pass_end_elem = false;
+
+ /**
+ * Constructs a HTMLWriter.
+ *
+ * @param writer writer to write output to
+ * @param doc the HTMLDocument to output
+ */
+ public HTMLWriter(Writer writer, HTMLDocument doc)
+ {
+ super(writer, doc);
+ outWriter = writer;
+ htmlDoc = doc;
+ openEmbeddedTagHashSet = new HashSet<HTML.Tag>();
+ } // public HTMLWriter(Writer writer, HTMLDocument doc)
+
+ /**
+ * Constructs a HTMLWriter which outputs a Html Fragment.
+ *
+ * @param writer <code>Writer</code> to write output to
+ * @param doc the <code>javax.swing.text.html.HTMLDocument</code>
+ * to output
+ * @param pos position to start outputing the document
+ * @param len amount to output the document
+ */
+ public HTMLWriter(Writer writer, HTMLDocument doc, int pos, int len)
+ {
+ super(writer, doc, pos, len);
+ outWriter = writer;
+ htmlDoc = doc;
+ openEmbeddedTagHashSet = new HashSet<HTML.Tag>();
+
+ doc_pos = pos;
+ doc_offset_remaining = pos;
+ doc_len = len;
+ doc_len_remaining = len;
+ htmlFragmentParentHashSet = new HashSet<Element>();
+ } // public HTMLWriter(Writer writer, HTMLDocument doc, int pos, int len)
+
+ /**
+ * Call this method to start outputing HTML.
+ *
+ * @throws IOException on any I/O exceptions
+ * @throws BadLocationException if a pos is not a valid position in the
+ * html doc element
+ */
+ public void write()
+ throws IOException, BadLocationException
+ {
+ Element rootElem = htmlDoc.getDefaultRootElement();
+
+ if (doc_pos == -1 && doc_len == -1)
+ {
+ // Normal traversal.
+ traverse(rootElem);
+ } // if(doc_pos == -1 && doc_len == -1)
+ else
+ {
+ // Html fragment traversal.
+ if (doc_pos == -1 || doc_len == -1)
+ throw new BadLocationException("Bad Location("
+ + doc_pos + ", " + doc_len + ")", doc_pos);
+
+ startElem = htmlDoc.getCharacterElement(doc_pos);
+
+ int start_offset = startElem.getStartOffset();
+
+ // Positions before start_offset will not be traversed, and thus
+ // will not be counted.
+ if (start_offset > 0)
+ doc_offset_remaining = doc_offset_remaining - start_offset;
+
+ Element tempParentElem = startElem;
+
+ while ((tempParentElem = tempParentElem.getParentElement()) != null)
+ {
+ if (!htmlFragmentParentHashSet.contains(tempParentElem))
+ htmlFragmentParentHashSet.add(tempParentElem);
+ } // while((tempParentElem = tempParentElem.getParentElement())
+ // != null)
+
+ // NOTE: 20061030 - fchoong - the last index should not be included.
+ endElem = htmlDoc.getCharacterElement(doc_pos + doc_len - 1);
+
+ tempParentElem = endElem;
+
+ while ((tempParentElem = tempParentElem.getParentElement()) != null)
+ {
+ if (!htmlFragmentParentHashSet.contains(tempParentElem))
+ htmlFragmentParentHashSet.add(tempParentElem);
+ } // while((tempParentElem = tempParentElem.getParentElement())
+ // != null)
+
+ traverseHtmlFragment(rootElem);
+
+ } // else
+
+ // NOTE: close out remaining open embeded tags.
+ HTML.Tag[] tag_arr =
+ openEmbeddedTagHashSet.toArray(new HTML.Tag[openEmbeddedTagHashSet.size()]);
+
+ for (int i = 0; i < tag_arr.length; i++)
+ {
+ writeRaw("</" + tag_arr[i].toString() + ">");
+ } // for(int i = 0; i < tag_arr.length; i++)
+
+ } // public void write() throws IOException, BadLocationException
+
+ /**
+ * Writes all the attributes in the attrSet, except for attrbutes with
+ * keys of <code>javax.swing.text.html.HTML.Tag</code>,
+ * <code>javax.swing.text.StyleConstants</code> or
+ * <code>javax.swing.text.html.HTML.Attribute.ENDTAG</code>.
+ *
+ * @param attrSet attrSet to write out
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ protected void writeAttributes(AttributeSet attrSet)
+ throws IOException
+ {
+ Enumeration<?> attrNameEnum = attrSet.getAttributeNames();
+
+ while (attrNameEnum.hasMoreElements())
+ {
+ Object key = attrNameEnum.nextElement();
+ Object value = attrSet.getAttribute(key);
+
+ // HTML.Attribute.ENDTAG is an instance, not a class.
+ if (!((key instanceof HTML.Tag) || (key instanceof StyleConstants)
+ || (key == HTML.Attribute.ENDTAG)))
+ {
+ if (key == HTML.Attribute.SELECTED)
+ writeRaw(" selected");
+ else if (key == HTML.Attribute.CHECKED)
+ writeRaw(" checked");
+ else
+ writeRaw(" " + key + "=\"" + value + "\"");
+ } // if(!((key instanceof HTML.Tag) || (key instanceof
+ // StyleConstants) || (key == HTML.Attribute.ENDTAG)))
+ } // while(attrNameEnum.hasMoreElements())
+
+ } // protected void writeAttributes(AttributeSet attrSet) throws IOException
+
+ /**
+ * Writes out an empty tag. i.e. a tag without any child elements.
+ *
+ * @param paramElem the element to output as an empty tag
+ *
+ * @throws IOException on any I/O exceptions
+ * @throws BadLocationException if a pos is not a valid position in the
+ * html doc element
+ */
+ protected void emptyTag(Element paramElem)
+ throws IOException, BadLocationException
+ {
+ String elem_name = paramElem.getName();
+ AttributeSet attrSet = paramElem.getAttributes();
+
+ writeRaw("<" + elem_name);
+ writeAttributes(attrSet);
+ writeRaw(">");
+
+ if (isBlockTag(attrSet))
+ {
+ writeRaw("</" + elem_name + ">");
+ } // if(isBlockTag(attrSet))
+
+ } // protected void emptyTag(Element paramElem)
+ // throws IOException, BadLocationException
+
+ /**
+ * Determines if it is a block tag or not.
+ *
+ * @param attrSet the attrSet of the element
+ *
+ * @return <code>true</code> if it is a block tag
+ * <code>false</code> if it is a not block tag
+ */
+ protected boolean isBlockTag(AttributeSet attrSet)
+ {
+ return ((HTML.Tag)
+ attrSet.getAttribute(StyleConstants.NameAttribute)).isBlock();
+ } // protected boolean isBlockTag(AttributeSet attrSet)
+
+ /**
+ * Writes out a start tag. Synthesized elements are skipped.
+ *
+ * @param paramElem the element to output as a start tag
+ * @throws IOException on any I/O exceptions
+ * @throws BadLocationException if a pos is not a valid position in the
+ * html doc element
+ */
+ protected void startTag(Element paramElem)
+ throws IOException, BadLocationException
+ {
+ // NOTE: Sysnthesized elements do no call this method at all.
+ String elem_name = paramElem.getName();
+ AttributeSet attrSet = paramElem.getAttributes();
+
+ indent();
+ writeRaw("<" + elem_name);
+ writeAttributes(attrSet);
+ writeRaw(">");
+ writeLineSeparator(); // Extra formatting to look more like the RI.
+ incrIndent();
+
+ } // protected void startTag(Element paramElem)
+ // throws IOException, BadLocationException
+
+ /**
+ * Writes out the contents of a textarea.
+ *
+ * @param attrSet the attrSet of the element to output as a text area
+ * @throws IOException on any I/O exceptions
+ * @throws BadLocationException if a pos is not a valid position in the
+ * html doc element
+ */
+ protected void textAreaContent(AttributeSet attrSet)
+ throws IOException, BadLocationException
+ {
+ writeLineSeparator(); // Extra formatting to look more like the RI.
+ indent();
+ writeRaw("<textarea");
+ writeAttributes(attrSet);
+ writeRaw(">");
+
+ Document tempDocument =
+ (Document) attrSet.getAttribute(StyleConstants.ModelAttribute);
+
+ writeRaw(tempDocument.getText(0, tempDocument.getLength()));
+ indent();
+ writeRaw("</textarea>");
+
+ } // protected void textAreaContent(AttributeSet attrSet)
+ // throws IOException, BadLocationException
+
+ /**
+ * Writes out text, within the appropriate range if it is specified.
+ *
+ * @param paramElem the element to output as a text
+ * @throws IOException on any I/O exceptions
+ * @throws BadLocationException if a pos is not a valid position in the
+ * html doc element
+ */
+ protected void text(Element paramElem)
+ throws IOException, BadLocationException
+ {
+ int offset = paramElem.getStartOffset();
+ int len = paramElem.getEndOffset() - paramElem.getStartOffset();
+ String txt_value = htmlDoc.getText(offset, len);
+
+ writeContent(txt_value);
+
+ } // protected void text(Element paramElem)
+ // throws IOException, BadLocationException
+
+ /**
+ * Writes out the contents of a select element.
+ *
+ * @param attrSet the attrSet of the element to output as a select box
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ protected void selectContent(AttributeSet attrSet)
+ throws IOException
+ {
+ writeLineSeparator(); // Extra formatting to look more like the RI.
+ indent();
+ writeRaw("<select");
+ writeAttributes(attrSet);
+ writeRaw(">");
+ incrIndent();
+ writeLineSeparator(); // extra formatting to look more like the RI.
+
+ ComboBoxModel comboBoxModel =
+ (ComboBoxModel) attrSet.getAttribute(StyleConstants.ModelAttribute);
+
+ for (int i = 0; i < comboBoxModel.getSize(); i++)
+ {
+ writeOption((Option) comboBoxModel.getElementAt(i));
+ } // for(int i = 0; i < comboBoxModel.getSize(); i++)
+
+ decrIndent();
+ indent();
+ writeRaw("</select>");
+
+ } // protected void selectContent(AttributeSet attrSet) throws IOException
+
+ /**
+ * Writes out the contents of an option element.
+ *
+ * @param option the option object to output as a select option
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ protected void writeOption(Option option)
+ throws IOException
+ {
+ indent();
+ writeRaw("<option");
+ writeAttributes(option.getAttributes());
+ writeRaw(">");
+
+ writeContent(option.getLabel());
+
+ writeRaw("</option>");
+ writeLineSeparator(); // extra formatting to look more like the RI.
+
+ } // protected void writeOption(Option option) throws IOException
+
+ /**
+ * Writes out an end tag.
+ *
+ * @param paramElem the element to output as an end tag
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ protected void endTag(Element paramElem)
+ throws IOException
+ {
+ String elem_name = paramElem.getName();
+
+ //writeLineSeparator(); // Extra formatting to look more like the RI.
+ decrIndent();
+ indent();
+ writeRaw("</" + elem_name + ">");
+ writeLineSeparator(); // Extra formatting to look more like the RI.
+
+ } // protected void endTag(Element paramElem) throws IOException
+
+ /**
+ * Writes out the comment.
+ *
+ * @param paramElem the element to output as a comment
+ */
+ protected void comment(Element paramElem)
+ throws IOException, BadLocationException
+ {
+ AttributeSet attrSet = paramElem.getAttributes();
+
+ String comment_str = (String) attrSet.getAttribute(HTML.Attribute.COMMENT);
+
+ writeRaw("<!--" + comment_str + "-->");
+
+ } // protected void comment(Element paramElem)
+ // throws IOException, BadLocationException
+
+ /**
+ * Determines if element is a synthesized
+ * <code>javax.swing.text.Element</code> or not.
+ *
+ * @param element the element to test
+ *
+ * @return <code>true</code> if it is a synthesized element,
+ * <code>false</code> if it is a not synthesized element
+ */
+ protected boolean synthesizedElement(Element element)
+ {
+ AttributeSet attrSet = element.getAttributes();
+ Object tagType = attrSet.getAttribute(StyleConstants.NameAttribute);
+
+ if (tagType == HTML.Tag.CONTENT || tagType == HTML.Tag.COMMENT
+ || tagType == HTML.Tag.IMPLIED)
+ return true;
+ else
+ return false;
+ } // protected boolean synthesizedElement(Element element)
+
+ /**
+ * Determines if
+ * <code>javax.swing.text.StyleConstants.NameAttribute</code>
+ * matches tag or not.
+ *
+ * @param attrSet the <code>javax.swing.text.AttributeSet</code> of
+ * element to be matched
+ * @param tag the HTML.Tag to match
+ *
+ * @return <code>true</code> if it matches,
+ * <code>false</code> if it does not match
+ */
+ protected boolean matchNameAttribute(AttributeSet attrSet, HTML.Tag tag)
+ {
+ Object tagType = attrSet.getAttribute(StyleConstants.NameAttribute);
+
+ if (tagType == tag)
+ return true;
+ else
+ return false;
+ } // protected boolean matchNameAttribute(AttributeSet attrSet,
+ // HTML.Tag tag)
+
+ /**
+ * Writes out an embedded tag. The tags not already in
+ * openEmbededTagHashSet will written out.
+ *
+ * @param attrSet the <code>javax.swing.text.AttributeSet</code> of
+ * the element to write out
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ protected void writeEmbeddedTags(AttributeSet attrSet)
+ throws IOException
+ {
+ Enumeration<?> attrNameEnum = attrSet.getAttributeNames();
+
+ while (attrNameEnum.hasMoreElements())
+ {
+ Object key = attrNameEnum.nextElement();
+ Object value = attrSet.getAttribute(key);
+
+ if (key instanceof HTML.Tag)
+ {
+ if (!openEmbeddedTagHashSet.contains(key))
+ {
+ writeRaw("<" + key);
+ writeAttributes((AttributeSet) value);
+ writeRaw(">");
+ openEmbeddedTagHashSet.add((HTML.Tag) key);
+ } // if(!openEmbededTagHashSet.contains(key))
+ } // if(key instanceof HTML.Tag)
+ } // while(attrNameEnum.hasMoreElements())
+
+ } // protected void writeEmbeddedTags(AttributeSet attrSet)
+ // throws IOException
+
+ /**
+ * Closes out an unwanted embedded tag. The tags from the
+ * openEmbededTagHashSet not found in attrSet will be written out.
+ *
+ * @param attrSet the AttributeSet of the element to write out
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ protected void closeOutUnwantedEmbeddedTags(AttributeSet attrSet)
+ throws IOException
+ {
+ HTML.Tag[] tag_arr =
+ openEmbeddedTagHashSet.toArray(new HTML.Tag[openEmbeddedTagHashSet.size()]);
+
+ for (int i = 0; i < tag_arr.length; i++)
+ {
+ HTML.Tag key = tag_arr[i];
+
+ if (!attrSet.isDefined(key))
+ {
+ writeRaw("</" + key.toString() + ">");
+ openEmbeddedTagHashSet.remove(key);
+ } // if(!attrSet.isDefined(key))
+ } // for(int i = 0; i < tag_arr.length; i++)
+
+ } // protected void closeOutUnwantedEmbeddedTags(AttributeSet attrSet)
+ // throws IOException
+
+ /**
+ * Writes out a line separator. Overwrites the parent to write out a new
+ * line.
+ *
+ * @throws IOException on any I/O exceptions.
+ */
+ protected void writeLineSeparator()
+ throws IOException
+ {
+ writeRaw(new_line_str);
+ } // protected void writeLineSeparator() throws IOException
+
+ /**
+ * Write to the writer. Character entites such as &lt;, &gt;
+ * are escaped appropriately.
+ *
+ * @param chars char array to write out
+ * @param off offset
+ * @param len length
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ protected void output(char[] chars, int off, int len)
+ throws IOException
+ {
+ CPStringBuilder strBuffer = new CPStringBuilder();
+
+ for (int i = 0; i < chars.length; i++)
+ {
+ if (isCharHtmlEntity(chars[i]))
+ strBuffer.append(escapeCharHtmlEntity(chars[i]));
+ else
+ strBuffer.append(chars[i]);
+ } // for(int i = 0; i < chars.length; i++)
+
+ writeRaw(strBuffer.toString());
+
+ } // protected void output(char[] chars, int off, int len)
+ // throws IOException
+
+ //-------------------------------------------------------------------------
+ // private methods
+
+ /**
+ * The main method used to traverse through the elements.
+ *
+ * @param paramElem element to traverse
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ private void traverse(Element paramElem)
+ throws IOException, BadLocationException
+ {
+ Element currElem = paramElem;
+
+ AttributeSet attrSet = currElem.getAttributes();
+
+ closeOutUnwantedEmbeddedTags(attrSet);
+
+ // handle the tag
+ if (synthesizedElement(paramElem))
+ {
+ if (matchNameAttribute(attrSet, HTML.Tag.CONTENT))
+ {
+ writeEmbeddedTags(attrSet);
+ text(currElem);
+ } // if(matchNameAttribute(attrSet, HTML.Tag.CONTENT))
+ else if (matchNameAttribute(attrSet, HTML.Tag.COMMENT))
+ {
+ comment(currElem);
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.COMMENT))
+ else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED))
+ {
+ int child_elem_count = currElem.getElementCount();
+
+ if (child_elem_count > 0)
+ {
+ for (int i = 0; i < child_elem_count; i++)
+ {
+ Element childElem = paramElem.getElement(i);
+
+ traverse(childElem);
+
+ } // for(int i = 0; i < child_elem_count; i++)
+ } // if(child_elem_count > 0)
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.IMPLIED))
+ } // if(synthesizedElement(paramElem))
+ else
+ {
+ // NOTE: 20061030 - fchoong - title is treated specially here.
+ // based on RI behavior.
+ if (matchNameAttribute(attrSet, HTML.Tag.TITLE))
+ {
+ boolean fg_is_end_tag = false;
+ Enumeration<?> attrNameEnum = attrSet.getAttributeNames();
+
+ while (attrNameEnum.hasMoreElements())
+ {
+ Object key = attrNameEnum.nextElement();
+ Object value = attrSet.getAttribute(key);
+
+ if (key == HTML.Attribute.ENDTAG && value.equals("true"))
+ fg_is_end_tag = true;
+ } // while(attrNameEnum.hasMoreElements())
+
+ if (fg_is_end_tag)
+ writeRaw("</title>");
+ else
+ {
+ indent();
+ writeRaw("<title>");
+
+ String title_str =
+ (String) htmlDoc.getProperty(HTMLDocument.TitleProperty);
+
+ if (title_str != null)
+ writeContent(title_str);
+
+ } // else
+ } // if(matchNameAttribute(attrSet, HTML.Tag.TITLE))
+ else if (matchNameAttribute(attrSet, HTML.Tag.PRE))
+ {
+ // We pursue more stringent formating here.
+ attrSet = paramElem.getAttributes();
+
+ indent();
+ writeRaw("<pre");
+ writeAttributes(attrSet);
+ writeRaw(">");
+
+ int child_elem_count = currElem.getElementCount();
+
+ for (int i = 0; i < child_elem_count; i++)
+ {
+ Element childElem = paramElem.getElement(i);
+
+ traverse(childElem);
+
+ } // for(int i = 0; i < child_elem_count; i++)
+
+ writeRaw("</pre>");
+
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.PRE))
+ else if (matchNameAttribute(attrSet, HTML.Tag.SELECT))
+ {
+ selectContent(attrSet);
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.SELECT))
+ else if (matchNameAttribute(attrSet, HTML.Tag.TEXTAREA))
+ {
+ textAreaContent(attrSet);
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.TEXTAREA))
+ else
+ {
+ int child_elem_count = currElem.getElementCount();
+
+ if (child_elem_count > 0)
+ {
+ startTag(currElem);
+
+ for (int i = 0; i < child_elem_count; i++)
+ {
+ Element childElem = paramElem.getElement(i);
+
+ traverse(childElem);
+
+ } // for(int i = 0; i < child_elem_count; i++)
+
+ endTag(currElem);
+
+ } // if(child_elem_count > 0)
+ else
+ {
+ emptyTag(currElem);
+ } // else
+ } // else
+ } // else
+
+ } // private void traverse(Element paramElem)
+ // throws IOException, BadLocationException
+
+ /**
+ * The method used to traverse through a html fragment.
+ *
+ * @param paramElem element to traverse
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ private void traverseHtmlFragment(Element paramElem)
+ throws IOException, BadLocationException
+ {
+ // NOTE: This method is similar to traverse(Element paramElem)
+ Element currElem = paramElem;
+
+ boolean fg_is_fragment_parent_elem = false;
+ boolean fg_is_start_and_end_elem = false;
+
+ if (htmlFragmentParentHashSet.contains(paramElem))
+ fg_is_fragment_parent_elem = true;
+
+ if (paramElem == startElem)
+ fg_pass_start_elem = true;
+
+ if (paramElem == startElem && paramElem == endElem)
+ fg_is_start_and_end_elem = true;
+
+ AttributeSet attrSet = currElem.getAttributes();
+
+ closeOutUnwantedEmbeddedTags(attrSet);
+
+ if (fg_is_fragment_parent_elem || (fg_pass_start_elem
+ && fg_pass_end_elem == false) || fg_is_start_and_end_elem)
+ {
+ // handle the tag
+ if (synthesizedElement(paramElem))
+ {
+ if (matchNameAttribute(attrSet, HTML.Tag.CONTENT))
+ {
+ writeEmbeddedTags(attrSet);
+
+ int content_offset = paramElem.getStartOffset();
+ int content_length = currElem.getEndOffset() - content_offset;
+
+ if (doc_offset_remaining > 0)
+ {
+ if (content_length > doc_offset_remaining)
+ {
+ int split_len = content_length;
+
+ split_len = split_len - doc_offset_remaining;
+
+ if (split_len > doc_len_remaining)
+ split_len = doc_len_remaining;
+
+ // we need to split it.
+ String txt_value = htmlDoc.getText(content_offset
+ + doc_offset_remaining, split_len);
+
+ writeContent(txt_value);
+
+ doc_offset_remaining = 0; // the offset is used up.
+ doc_len_remaining = doc_len_remaining - split_len;
+ } // if(content_length > doc_offset_remaining)
+ else
+ {
+ // doc_offset_remaining is greater than the entire
+ // length of content
+ doc_offset_remaining = doc_offset_remaining
+ - content_length;
+ } // else
+ } // if(doc_offset_remaining > 0)
+ else if (content_length <= doc_len_remaining)
+ {
+ // we can fit the entire content.
+ text(currElem);
+ doc_len_remaining = doc_len_remaining - content_length;
+ } // else if(content_length <= doc_len_remaining)
+ else
+ {
+ // we need to split it.
+ String txt_value = htmlDoc.getText(content_offset,
+ doc_len_remaining);
+
+ writeContent(txt_value);
+
+ doc_len_remaining = 0;
+ } // else
+
+ } // if(matchNameAttribute(attrSet, HTML.Tag.CONTENT))
+ else if (matchNameAttribute(attrSet, HTML.Tag.COMMENT))
+ {
+ comment(currElem);
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.COMMENT))
+ else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED))
+ {
+ int child_elem_count = currElem.getElementCount();
+
+ if (child_elem_count > 0)
+ {
+ for (int i = 0; i < child_elem_count; i++)
+ {
+ Element childElem = paramElem.getElement(i);
+
+ traverseHtmlFragment(childElem);
+
+ } // for(int i = 0; i < child_elem_count; i++)
+ } // if(child_elem_count > 0)
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.IMPLIED))
+ } // if(synthesizedElement(paramElem))
+ else
+ {
+ // NOTE: 20061030 - fchoong - the isLeaf() condition seems to
+ // generate the closest behavior to the RI.
+ if (paramElem.isLeaf())
+ {
+ if (doc_offset_remaining > 0)
+ {
+ doc_offset_remaining--;
+ } // if(doc_offset_remaining > 0)
+ else if (doc_len_remaining > 0)
+ {
+ doc_len_remaining--;
+ } // else if(doc_len_remaining > 0)
+ } // if(paramElem.isLeaf())
+
+ // NOTE: 20061030 - fchoong - title is treated specially here.
+ // based on RI behavior.
+ if (matchNameAttribute(attrSet, HTML.Tag.TITLE))
+ {
+ boolean fg_is_end_tag = false;
+ Enumeration<?> attrNameEnum = attrSet.getAttributeNames();
+
+ while (attrNameEnum.hasMoreElements())
+ {
+ Object key = attrNameEnum.nextElement();
+ Object value = attrSet.getAttribute(key);
+
+ if (key == HTML.Attribute.ENDTAG && value.equals("true"))
+ fg_is_end_tag = true;
+ } // while(attrNameEnum.hasMoreElements())
+
+ if (fg_is_end_tag)
+ writeRaw("</title>");
+ else
+ {
+ indent();
+ writeRaw("<title>");
+
+ String title_str =
+ (String) htmlDoc.getProperty(HTMLDocument.TitleProperty);
+
+ if (title_str != null)
+ writeContent(title_str);
+
+ } // else
+ } // if(matchNameAttribute(attrSet, HTML.Tag.TITLE))
+ else if (matchNameAttribute(attrSet, HTML.Tag.PRE))
+ {
+ // We pursue more stringent formating here.
+ attrSet = paramElem.getAttributes();
+
+ indent();
+ writeRaw("<pre");
+ writeAttributes(attrSet);
+ writeRaw(">");
+
+ int child_elem_count = currElem.getElementCount();
+
+ for (int i = 0; i < child_elem_count; i++)
+ {
+ Element childElem = paramElem.getElement(i);
+
+ traverseHtmlFragment(childElem);
+
+ } // for(int i = 0; i < child_elem_count; i++)
+
+ writeRaw("</pre>");
+
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.PRE))
+ else if (matchNameAttribute(attrSet, HTML.Tag.SELECT))
+ {
+ selectContent(attrSet);
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.SELECT))
+ else if (matchNameAttribute(attrSet, HTML.Tag.TEXTAREA))
+ {
+ textAreaContent(attrSet);
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.TEXTAREA))
+ else
+ {
+ int child_elem_count = currElem.getElementCount();
+
+ if (child_elem_count > 0)
+ {
+ startTag(currElem);
+
+ for (int i = 0; i < child_elem_count; i++)
+ {
+ Element childElem = paramElem.getElement(i);
+
+ traverseHtmlFragment(childElem);
+
+ } // for(int i = 0; i < child_elem_count; i++)
+
+ endTag(currElem);
+
+ } // if(child_elem_count > 0)
+ else
+ {
+ emptyTag(currElem);
+ } // else
+ } // else
+ } // else
+
+ } // if(fg_is_fragment_parent_elem || (fg_pass_start_elem
+ // && fg_pass_end_elem == false) || fg_is_start_and_end_elem)
+
+ if (paramElem == endElem)
+ fg_pass_end_elem = true;
+
+ } // private void traverseHtmlFragment(Element paramElem)
+ // throws IOException, BadLocationException
+
+ /**
+ * Write to the writer without any modifications.
+ *
+ * @param param_str the str to write out
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ private void writeRaw(String param_str)
+ throws IOException
+ {
+ super.output(param_str.toCharArray(), 0, param_str.length());
+ } // private void writeRaw(char[] chars, int off, int len)
+ // throws IOException
+
+ /**
+ * Write to the writer, escaping HTML character entitie where neccessary.
+ *
+ * @param param_str the str to write out
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ private void writeContent(String param_str)
+ throws IOException
+ {
+ char[] str_char_arr = param_str.toCharArray();
+
+ if (hasHtmlEntity(param_str))
+ output(str_char_arr, 0, str_char_arr.length);
+ else
+ super.output(str_char_arr, 0, str_char_arr.length);
+
+ } // private void writeContent(String param_str) throws IOException
+
+ /**
+ * Use this for debugging. Writes out all attributes regardless of type.
+ *
+ * @param attrSet the <code>javax.swing.text.AttributeSet</code> to
+ * write out
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ private void writeAllAttributes(AttributeSet attrSet)
+ throws IOException
+ {
+ Enumeration<?> attrNameEnum = attrSet.getAttributeNames();
+
+ while (attrNameEnum.hasMoreElements())
+ {
+ Object key = attrNameEnum.nextElement();
+ Object value = attrSet.getAttribute(key);
+
+ writeRaw(" " + key + "=\"" + value + "\"");
+ writeRaw(" " + key.getClass().toString() + "=\""
+ + value.getClass().toString() + "\"");
+ } // while(attrNameEnum.hasMoreElements())
+
+ } // private void writeAllAttributes(AttributeSet attrSet)
+ // throws IOException
+
+ /**
+ * Tests if the str contains any html entities.
+ *
+ * @param param_str the str to test
+ *
+ * @return <code>true</code> if it has a html entity
+ * <code>false</code> if it does not have a html entity
+ */
+ private boolean hasHtmlEntity(String param_str)
+ {
+ boolean ret_bool = false;
+
+ for (int i = 0; i < html_entity_char_arr.length; i++)
+ {
+ if (param_str.indexOf(html_entity_char_arr[i]) != -1)
+ {
+ ret_bool = true;
+ break;
+ } // if(param_str.indexOf(html_entity_char_arr[i]) != -1)
+ } // for(int i = 0; i < html_entity_char_arr.length; i++)
+
+ return ret_bool;
+ } // private boolean hasHtmlEntity(String param_str)
+
+ /**
+ * Tests if the char is a html entities.
+ *
+ * @param param_char the char to test
+ *
+ * @return <code>true</code> if it is a html entity
+ * <code>false</code> if it is not a html entity.
+ */
+ private boolean isCharHtmlEntity(char param_char)
+ {
+ boolean ret_bool = false;
+
+ for (int i = 0; i < html_entity_char_arr.length; i++)
+ {
+ if (param_char == html_entity_char_arr[i])
+ {
+ ret_bool = true;
+ break;
+ } // if(param_char == html_entity_char_arr[i])
+ } // for(int i = 0; i < html_entity_char_arr.length; i++)
+
+ return ret_bool;
+ } // private boolean hasHtmlEntity(String param_str)
+
+ /**
+ * Escape html entities.
+ *
+ * @param param_char the char to escape
+ *
+ * @return escaped html entity. Original char is returned as a str if is
+ * is not a html entity
+ */
+ private String escapeCharHtmlEntity(char param_char)
+ {
+ String ret_str = "" + param_char;
+
+ for (int i = 0; i < html_entity_char_arr.length; i++)
+ {
+ if (param_char == html_entity_char_arr[i])
+ {
+ ret_str = html_entity_escape_str_arr[i];
+ break;
+ } // if(param_char == html_entity_char_arr[i])
+ } // for(int i = 0; i < html_entity_char_arr.length; i++)
+
+ return ret_str;
+ } // private String escapeCharHtmlEntity(char param_char)
+
+} // public class HTMLWriter extends AbstractWriter
diff --git a/libjava/classpath/javax/swing/text/html/ImageView.java b/libjava/classpath/javax/swing/text/html/ImageView.java
new file mode 100644
index 000000000..bdbe9b3bb
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/ImageView.java
@@ -0,0 +1,591 @@
+package javax.swing.text.html;
+
+import gnu.javax.swing.text.html.ImageViewIconFactory;
+import gnu.javax.swing.text.html.css.Length;
+
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.MediaTracker;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.Toolkit;
+import java.awt.image.ImageObserver;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.swing.Icon;
+import javax.swing.SwingUtilities;
+import javax.swing.text.AbstractDocument;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.View;
+import javax.swing.text.Position.Bias;
+import javax.swing.text.html.HTML.Attribute;
+
+/**
+ * A view, representing a single image, represented by the HTML IMG tag.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class ImageView extends View
+{
+ /**
+ * Tracks image loading state and performs the necessary layout updates.
+ */
+ class Observer
+ implements ImageObserver
+ {
+
+ public boolean imageUpdate(Image image, int flags, int x, int y, int width, int height)
+ {
+ boolean widthChanged = false;
+ if ((flags & ImageObserver.WIDTH) != 0 && spans[X_AXIS] == null)
+ widthChanged = true;
+ boolean heightChanged = false;
+ if ((flags & ImageObserver.HEIGHT) != 0 && spans[Y_AXIS] == null)
+ heightChanged = true;
+ if (widthChanged || heightChanged)
+ safePreferenceChanged(ImageView.this, widthChanged, heightChanged);
+ boolean ret = (flags & ALLBITS) != 0;
+ return ret;
+ }
+
+ }
+
+ /**
+ * True if the image loads synchronuosly (on demand). By default, the image
+ * loads asynchronuosly.
+ */
+ boolean loadOnDemand;
+
+ /**
+ * The image icon, wrapping the image,
+ */
+ Image image;
+
+ /**
+ * The image state.
+ */
+ byte imageState = MediaTracker.LOADING;
+
+ /**
+ * True when the image needs re-loading, false otherwise.
+ */
+ private boolean reloadImage;
+
+ /**
+ * True when the image properties need re-loading, false otherwise.
+ */
+ private boolean reloadProperties;
+
+ /**
+ * True when the width is set as CSS/HTML attribute.
+ */
+ private boolean haveWidth;
+
+ /**
+ * True when the height is set as CSS/HTML attribute.
+ */
+ private boolean haveHeight;
+
+ /**
+ * True when the image is currently loading.
+ */
+ private boolean loading;
+
+ /**
+ * The current width of the image.
+ */
+ private int width;
+
+ /**
+ * The current height of the image.
+ */
+ private int height;
+
+ /**
+ * Our ImageObserver for tracking the loading state.
+ */
+ private ImageObserver observer;
+
+ /**
+ * The CSS width and height.
+ *
+ * Package private to avoid synthetic accessor methods.
+ */
+ Length[] spans;
+
+ /**
+ * The cached attributes.
+ */
+ private AttributeSet attributes;
+
+ /**
+ * Creates the image view that represents the given element.
+ *
+ * @param element the element, represented by this image view.
+ */
+ public ImageView(Element element)
+ {
+ super(element);
+ spans = new Length[2];
+ observer = new Observer();
+ reloadProperties = true;
+ reloadImage = true;
+ loadOnDemand = false;
+ }
+
+ /**
+ * Load or reload the image. This method initiates the image reloading. After
+ * the image is ready, the repaint event will be scheduled. The current image,
+ * if it already exists, will be discarded.
+ */
+ private void reloadImage()
+ {
+ loading = true;
+ reloadImage = false;
+ haveWidth = false;
+ haveHeight = false;
+ image = null;
+ width = 0;
+ height = 0;
+ try
+ {
+ loadImage();
+ updateSize();
+ }
+ finally
+ {
+ loading = false;
+ }
+ }
+
+ /**
+ * Get the image alignment. This method works handling standart alignment
+ * attributes in the HTML IMG tag (align = top bottom middle left right).
+ * Depending from the parameter, either horizontal or vertical alingment
+ * information is returned.
+ *
+ * @param axis -
+ * either X_AXIS or Y_AXIS
+ */
+ public float getAlignment(int axis)
+ {
+ AttributeSet attrs = getAttributes();
+ Object al = attrs.getAttribute(Attribute.ALIGN);
+
+ // Default is top left aligned.
+ if (al == null)
+ return 0.0f;
+
+ String align = al.toString();
+
+ if (axis == View.X_AXIS)
+ {
+ if (align.equals("middle"))
+ return 0.5f;
+ else if (align.equals("left"))
+ return 0.0f;
+ else if (align.equals("right"))
+ return 1.0f;
+ else
+ return 0.0f;
+ }
+ else if (axis == View.Y_AXIS)
+ {
+ if (align.equals("middle"))
+ return 0.5f;
+ else if (align.equals("top"))
+ return 0.0f;
+ else if (align.equals("bottom"))
+ return 1.0f;
+ else
+ return 0.0f;
+ }
+ else
+ throw new IllegalArgumentException("axis " + axis);
+ }
+
+ /**
+ * Get the text that should be shown as the image replacement and also as the
+ * image tool tip text. The method returns the value of the attribute, having
+ * the name {@link Attribute#ALT}. If there is no such attribute, the image
+ * name from the url is returned. If the URL is not available, the empty
+ * string is returned.
+ */
+ public String getAltText()
+ {
+ Object rt = getAttributes().getAttribute(Attribute.ALT);
+ if (rt != null)
+ return rt.toString();
+ else
+ {
+ URL u = getImageURL();
+ if (u == null)
+ return "";
+ else
+ return u.getFile();
+ }
+ }
+
+ /**
+ * Returns the combination of the document and the style sheet attributes.
+ */
+ public AttributeSet getAttributes()
+ {
+ if (attributes == null)
+ attributes = getStyleSheet().getViewAttributes(this);
+ return attributes;
+ }
+
+ /**
+ * Get the image to render. May return null if the image is not yet loaded.
+ */
+ public Image getImage()
+ {
+ updateState();
+ return image;
+ }
+
+ /**
+ * Get the URL location of the image to render. If this method returns null,
+ * the "no image" icon is rendered instead. By defaul, url must be present as
+ * the "src" property of the IMG tag. If it is missing, null is returned and
+ * the "no image" icon is rendered.
+ *
+ * @return the URL location of the image to render.
+ */
+ public URL getImageURL()
+ {
+ Element el = getElement();
+ String src = (String) el.getAttributes().getAttribute(Attribute.SRC);
+ URL url = null;
+ if (src != null)
+ {
+ URL base = ((HTMLDocument) getDocument()).getBase();
+ try
+ {
+ url = new URL(base, src);
+ }
+ catch (MalformedURLException ex)
+ {
+ // Return null.
+ }
+ }
+ return url;
+ }
+
+ /**
+ * Get the icon that should be displayed while the image is loading and hence
+ * not yet available.
+ *
+ * @return an icon, showing a non broken sheet of paper with image.
+ */
+ public Icon getLoadingImageIcon()
+ {
+ return ImageViewIconFactory.getLoadingImageIcon();
+ }
+
+ /**
+ * Get the image loading strategy.
+ *
+ * @return false (default) if the image is loaded when the view is
+ * constructed, true if the image is only loaded on demand when
+ * rendering.
+ */
+ public boolean getLoadsSynchronously()
+ {
+ return loadOnDemand;
+ }
+
+ /**
+ * Get the icon that should be displayed when the image is not available.
+ *
+ * @return an icon, showing a broken sheet of paper with image.
+ */
+ public Icon getNoImageIcon()
+ {
+ return ImageViewIconFactory.getNoImageIcon();
+ }
+
+ /**
+ * Get the preferred span of the image along the axis. The image size is first
+ * requested to the attributes {@link Attribute#WIDTH} and
+ * {@link Attribute#HEIGHT}. If they are missing, and the image is already
+ * loaded, the image size is returned. If there are no attributes, and the
+ * image is not loaded, zero is returned.
+ *
+ * @param axis -
+ * either X_AXIS or Y_AXIS
+ * @return either width of height of the image, depending on the axis.
+ */
+ public float getPreferredSpan(int axis)
+ {
+ Image image = getImage();
+
+ if (axis == View.X_AXIS)
+ {
+ if (spans[axis] != null)
+ return spans[axis].getValue();
+ else if (image != null)
+ return image.getWidth(getContainer());
+ else
+ return getNoImageIcon().getIconWidth();
+ }
+ else if (axis == View.Y_AXIS)
+ {
+ if (spans[axis] != null)
+ return spans[axis].getValue();
+ else if (image != null)
+ return image.getHeight(getContainer());
+ else
+ return getNoImageIcon().getIconHeight();
+ }
+ else
+ throw new IllegalArgumentException("axis " + axis);
+ }
+
+ /**
+ * Get the associated style sheet from the document.
+ *
+ * @return the associated style sheet.
+ */
+ protected StyleSheet getStyleSheet()
+ {
+ HTMLDocument doc = (HTMLDocument) getDocument();
+ return doc.getStyleSheet();
+ }
+
+ /**
+ * Get the tool tip text. This is overridden to return the value of the
+ * {@link #getAltText()}. The parameters are ignored.
+ *
+ * @return that is returned by getAltText().
+ */
+ public String getToolTipText(float x, float y, Shape shape)
+ {
+ return getAltText();
+ }
+
+ /**
+ * Paints the image or one of the two image state icons. The image is resized
+ * to the shape bounds. If there is no image available, the alternative text
+ * is displayed besides the image state icon.
+ *
+ * @param g
+ * the Graphics, used for painting.
+ * @param bounds
+ * the bounds of the region where the image or replacing icon must be
+ * painted.
+ */
+ public void paint(Graphics g, Shape bounds)
+ {
+ updateState();
+ Rectangle r = bounds instanceof Rectangle ? (Rectangle) bounds
+ : bounds.getBounds();
+ Image image = getImage();
+ if (image != null)
+ {
+ g.drawImage(image, r.x, r.y, r.width, r.height, observer);
+ }
+ else
+ {
+ Icon icon = getNoImageIcon();
+ if (icon != null)
+ icon.paintIcon(getContainer(), g, r.x, r.y);
+ }
+ }
+
+ /**
+ * Set if the image should be loaded only when needed (synchronuosly). By
+ * default, the image loads asynchronuosly. If the image is not yet ready, the
+ * icon, returned by the {@link #getLoadingImageIcon()}, is displayed.
+ */
+ public void setLoadsSynchronously(boolean load_on_demand)
+ {
+ loadOnDemand = load_on_demand;
+ }
+
+ /**
+ * Update all cached properties from the attribute set, returned by the
+ * {@link #getAttributes}.
+ */
+ protected void setPropertiesFromAttributes()
+ {
+ AttributeSet atts = getAttributes();
+ StyleSheet ss = getStyleSheet();
+ float emBase = ss.getEMBase(atts);
+ float exBase = ss.getEXBase(atts);
+ spans[X_AXIS] = (Length) atts.getAttribute(CSS.Attribute.WIDTH);
+ if (spans[X_AXIS] != null)
+ {
+ spans[X_AXIS].setFontBases(emBase, exBase);
+ }
+ spans[Y_AXIS] = (Length) atts.getAttribute(CSS.Attribute.HEIGHT);
+ if (spans[Y_AXIS] != null)
+ {
+ spans[Y_AXIS].setFontBases(emBase, exBase);
+ }
+ }
+
+ /**
+ * Maps the picture co-ordinates into the image position in the model. As the
+ * image is not divideable, this is currently implemented always to return the
+ * start offset.
+ */
+ public int viewToModel(float x, float y, Shape shape, Bias[] bias)
+ {
+ return getStartOffset();
+ }
+
+ /**
+ * This is currently implemented always to return the area of the image view,
+ * as the image is not divideable by character positions.
+ *
+ * @param pos character position
+ * @param area of the image view
+ * @param bias bias
+ *
+ * @return the shape, where the given character position should be mapped.
+ */
+ public Shape modelToView(int pos, Shape area, Bias bias)
+ throws BadLocationException
+ {
+ return area;
+ }
+
+ /**
+ * Starts loading the image asynchronuosly. If the image must be loaded
+ * synchronuosly instead, the {@link #setLoadsSynchronously} must be
+ * called before calling this method. The passed parameters are not used.
+ */
+ public void setSize(float width, float height)
+ {
+ updateState();
+ // TODO: Implement this when we have an alt view for the alt=... attribute.
+ }
+
+ /**
+ * This makes sure that the image and properties have been loaded.
+ */
+ private void updateState()
+ {
+ if (reloadImage)
+ reloadImage();
+ if (reloadProperties)
+ setPropertiesFromAttributes();
+ }
+
+ /**
+ * Actually loads the image.
+ */
+ private void loadImage()
+ {
+ URL src = getImageURL();
+ Image newImage = null;
+ if (src != null)
+ {
+ // Call getImage(URL) to allow the toolkit caching of that image URL.
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ newImage = tk.getImage(src);
+ tk.prepareImage(newImage, -1, -1, observer);
+ if (newImage != null && getLoadsSynchronously())
+ {
+ // Load image synchronously.
+ MediaTracker tracker = new MediaTracker(getContainer());
+ tracker.addImage(newImage, 0);
+ try
+ {
+ tracker.waitForID(0);
+ }
+ catch (InterruptedException ex)
+ {
+ Thread.interrupted();
+ }
+
+ }
+ }
+ image = newImage;
+ }
+
+ /**
+ * Updates the size parameters of the image.
+ */
+ private void updateSize()
+ {
+ int newW = 0;
+ int newH = 0;
+ Image newIm = getImage();
+ if (newIm != null)
+ {
+ // Fetch width.
+ Length l = spans[X_AXIS];
+ if (l != null)
+ {
+ newW = (int) l.getValue();
+ haveWidth = true;
+ }
+ else
+ {
+ newW = newIm.getWidth(observer);
+ }
+ // Fetch height.
+ l = spans[Y_AXIS];
+ if (l != null)
+ {
+ newH = (int) l.getValue();
+ haveHeight = true;
+ }
+ else
+ {
+ newW = newIm.getWidth(observer);
+ }
+ // Go and trigger loading.
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ if (haveWidth || haveHeight)
+ tk.prepareImage(newIm, width, height, observer);
+ else
+ tk.prepareImage(newIm, -1, -1, observer);
+ }
+ }
+
+ /**
+ * Calls preferenceChanged from the event dispatch thread and within
+ * a read lock to protect us from threading issues.
+ *
+ * @param v the view
+ * @param width true when the width changed
+ * @param height true when the height changed
+ */
+ void safePreferenceChanged(final View v, final boolean width,
+ final boolean height)
+ {
+ if (SwingUtilities.isEventDispatchThread())
+ {
+ Document doc = getDocument();
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readLock();
+ try
+ {
+ preferenceChanged(v, width, height);
+ }
+ finally
+ {
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readUnlock();
+ }
+ }
+ else
+ {
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ safePreferenceChanged(v, width, height);
+ }
+ });
+ }
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/InlineView.java b/libjava/classpath/javax/swing/text/html/InlineView.java
new file mode 100644
index 000000000..5376c6b9d
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/InlineView.java
@@ -0,0 +1,307 @@
+/* InlineView.java -- Renders HTML content
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import java.awt.FontMetrics;
+import java.awt.Shape;
+import java.text.BreakIterator;
+
+import javax.swing.event.DocumentEvent;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.LabelView;
+import javax.swing.text.Segment;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+
+/**
+ * Renders HTML content (identified by {@link HTML.Tag#CONTENT}). This is
+ * basically a {@link LabelView} that is adjusted to understand styles defined
+ * by stylesheets.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class InlineView
+ extends LabelView
+{
+
+ /**
+ * The attributes used by this view.
+ */
+ private AttributeSet attributes;
+
+ /**
+ * The span of the longest word in this view.
+ *
+ * @see #getLongestWord()
+ */
+ private float longestWord;
+
+ /**
+ * Indicates if we may wrap or not.
+ */
+ private boolean nowrap;
+
+ /**
+ * Creates a new <code>InlineView</code> that renders the specified element.
+ *
+ * @param element the element for this view
+ */
+ public InlineView(Element element)
+ {
+ super(element);
+ }
+
+ /**
+ * Receives notification that something was inserted into the document in
+ * a location that this view is responsible for.
+ *
+ * @param e the document event
+ * @param a the current allocation of this view
+ * @param f the view factory for creating new views
+ *
+ * @since 1.5
+ */
+ public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f)
+ {
+ // FIXME: What to do here?
+ super.insertUpdate(e, a, f);
+ }
+
+ /**
+ * Receives notification that something was removed from the document in
+ * a location that this view is responsible for.
+ *
+ * @param e the document event
+ * @param a the current allocation of this view
+ * @param f the view factory for creating new views
+ *
+ * @since 1.5
+ */
+ public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f)
+ {
+ // FIXME: What to do here?
+ super.removeUpdate(e, a, f);
+ }
+
+ /**
+ * Receives notification that attributes have changed in the document in
+ * a location that this view is responsible for. This calls
+ * {@link #setPropertiesFromAttributes}.
+ *
+ * @param e the document event
+ * @param a the current allocation of this view
+ * @param f the view factory for creating new views
+ *
+ * @since 1.5
+ */
+ public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f)
+ {
+ super.changedUpdate(e, a, f);
+ StyleSheet ss = getStyleSheet();
+ attributes = ss.getViewAttributes(this);
+ preferenceChanged(null, true, true);
+ setPropertiesFromAttributes();
+ }
+
+ /**
+ * Returns the attributes that are used for rendering. This is implemented
+ * to multiplex the attributes specified in the model with a stylesheet.
+ *
+ * @return the attributes that are used for rendering
+ */
+ public AttributeSet getAttributes()
+ {
+ if (attributes == null)
+ {
+ StyleSheet ss = getStyleSheet();
+ attributes = ss.getViewAttributes(this);
+ }
+ return attributes;
+ }
+
+
+ public int getBreakWeight(int axis, float pos, float len)
+ {
+ int weight;
+ if (nowrap)
+ weight = BadBreakWeight;
+ else
+ weight = super.getBreakWeight(axis, pos, len);
+ return weight;
+ }
+
+ public View breakView(int axis, int offset, float pos, float len)
+ {
+ // FIXME: Implement this.
+ return super.breakView(axis, offset, pos, len);
+ }
+
+ /**
+ * Loads the character style properties from the stylesheet.
+ */
+ protected void setPropertiesFromAttributes()
+ {
+ super.setPropertiesFromAttributes();
+ AttributeSet atts = getAttributes();
+ Object o = atts.getAttribute(CSS.Attribute.TEXT_DECORATION);
+
+ // Check for underline.
+ boolean b = false;
+ if (o != null && o.toString().contains("underline"))
+ b = true;
+ setUnderline(b);
+
+ // Check for line-through.
+ b = false;
+ if (o != null && o.toString().contains("line-through"))
+ b = true;
+ setStrikeThrough(b);
+
+ // Check for vertical alignment (subscript/superscript).
+ o = atts.getAttribute(CSS.Attribute.VERTICAL_ALIGN);
+
+ // Subscript.
+ b = false;
+ if (o != null && o.toString().contains("sub"))
+ b = true;
+ setSubscript(b);
+
+ // Superscript.
+ b = false;
+ if (o != null && o.toString().contains("sup"))
+ b = true;
+ setSuperscript(b);
+
+ // Fetch nowrap setting.
+ o = atts.getAttribute(CSS.Attribute.WHITE_SPACE);
+ if (o != null && o.equals("nowrap"))
+ nowrap = true;
+ else
+ nowrap = false;
+ }
+
+ /**
+ * Returns the stylesheet used by this view. This returns the stylesheet
+ * of the <code>HTMLDocument</code> that is rendered by this view.
+ *
+ * @return the stylesheet used by this view
+ */
+ protected StyleSheet getStyleSheet()
+ {
+ Document doc = getDocument();
+ StyleSheet styleSheet = null;
+ if (doc instanceof HTMLDocument)
+ styleSheet = ((HTMLDocument) doc).getStyleSheet();
+ return styleSheet;
+ }
+
+ /**
+ * Returns the minimum span for the specified axis. This returns the
+ * width of the longest word for the X axis and the super behaviour for
+ * the Y axis. This is a slight deviation from the reference implementation.
+ * IMO this should improve rendering behaviour so that an InlineView never
+ * gets smaller than the longest word in it.
+ */
+ public float getMinimumSpan(int axis)
+ {
+ float min = super.getMinimumSpan(axis);
+ if (axis == X_AXIS)
+ min = Math.max(getLongestWord(), min);
+ return min;
+ }
+
+ /**
+ * Returns the span of the longest word in this view.
+ *
+ * @return the span of the longest word in this view
+ */
+ private float getLongestWord()
+ {
+ if (longestWord == -1)
+ longestWord = calculateLongestWord();
+ return longestWord;
+ }
+
+ /**
+ * Calculates the span of the longest word in this view.
+ *
+ * @return the span of the longest word in this view
+ */
+ private float calculateLongestWord()
+ {
+ float span = 0;
+ try
+ {
+ Document doc = getDocument();
+ int p0 = getStartOffset();
+ int p1 = getEndOffset();
+ Segment s = new Segment();
+ doc.getText(p0, p1 - p0, s);
+ BreakIterator iter = BreakIterator.getWordInstance();
+ iter.setText(s);
+ int wordStart = p0;
+ int wordEnd = p0;
+ int start = iter.first();
+ for (int end = iter.next(); end != BreakIterator.DONE;
+ start = end, end = iter.next())
+ {
+ if ((end - start) > (wordEnd - wordStart))
+ {
+ wordStart = start;
+ wordEnd = end;
+ }
+ }
+ if (wordEnd - wordStart > 0)
+ {
+ FontMetrics fm = getFontMetrics();
+ int offset = s.offset + wordStart - s.getBeginIndex();
+ span = fm.charsWidth(s.array, offset, wordEnd - wordStart);
+ }
+ }
+ catch (BadLocationException ex)
+ {
+ // Return 0.
+ }
+ return span;
+ }
+
+}
diff --git a/libjava/classpath/javax/swing/text/html/ListView.java b/libjava/classpath/javax/swing/text/html/ListView.java
new file mode 100644
index 000000000..f05051a4d
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/ListView.java
@@ -0,0 +1,128 @@
+/* ListView.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+import javax.swing.text.Element;
+
+/**
+ * A View to render HTML lists, like the <code>&lt;ul&gt;</code> and
+ * <code>&lt;ol&gt;</code> tags.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class ListView
+ extends BlockView
+{
+
+ /**
+ * The painter used to paint the list items.
+ */
+ private StyleSheet.ListPainter painter;
+
+ /**
+ * Creates a new <code>ListView</code> for the specified element.
+ *
+ * @param el the element to create a list view for
+ */
+ public ListView(Element el)
+ {
+ super(el, Y_AXIS);
+ }
+
+ /**
+ * Returns the alignment of this view along the specified axis.
+ *
+ * This returns <code>0.5</code> unconditionally.
+ *
+ * @param axis the axis
+ *
+ * @return the alignment of this view along the specified axis
+ */
+ public float getAlignment(int axis)
+ {
+ if (axis != X_AXIS && axis != Y_AXIS)
+ throw new IllegalArgumentException("Illegal axis parameter: " + axis);
+
+ return 0.5F;
+ }
+
+ /**
+ * Paints the <code>ListView</code>.
+ *
+ * @param g the graphics context to use for painting
+ * @param allocation the allocation given to this view
+ */
+ public void paint(Graphics g, Shape allocation)
+ {
+ super.paint(g, allocation);
+ }
+
+ /**
+ * Paints the child with the specified index into the specified allocation.
+ *
+ * This implementation forwards to the list painter fetched from the
+ * {@link StyleSheet} and then calls
+ * <code>super.paintChild(g, a, index)</code>.
+ *
+ * @param g the graphics context to use
+ * @param a the allocation for the child
+ * @param index the child index
+ */
+ protected void paintChild(Graphics g, Rectangle a, int index)
+ {
+ painter.paint(g, a.x, a.y, a.width, a.height, this, index);
+ super.paintChild(g, a, index);
+ }
+
+ /**
+ * Fetches this view's properties from the style attributes of this view's
+ * element.
+ *
+ * This forwards to super and then fetches a {@link StyleSheet.ListPainter}
+ * from the stylesheet suitable for painting the list.
+ */
+ protected void setPropertiesFromAttributes()
+ {
+ super.setPropertiesFromAttributes();
+ painter = getStyleSheet().getListPainter(getAttributes());
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/MinimalHTMLWriter.java b/libjava/classpath/javax/swing/text/html/MinimalHTMLWriter.java
new file mode 100644
index 000000000..3dddfc3de
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/MinimalHTMLWriter.java
@@ -0,0 +1,453 @@
+/* MinimalHTMLWriter.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import javax.swing.text.AttributeSet;
+import javax.swing.text.AbstractWriter;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.DefaultStyledDocument;
+import javax.swing.text.Element;
+import javax.swing.text.ElementIterator;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.Style;
+import javax.swing.text.StyledDocument;
+import java.io.Writer;
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Enumeration;
+import java.awt.Color;
+
+/**
+ * MinimalHTMLWriter,
+ * A minimal AbstractWriter implementation for HTML.
+ *
+ * @author Sven de Marothy
+ */
+public class MinimalHTMLWriter extends AbstractWriter
+{
+ private StyledDocument doc;
+ private Deque<String> tagStack;
+ private boolean inFontTag = false;
+
+ /**
+ * Constructs a MinimalHTMLWriter.
+ * @param w - a Writer, for output.
+ * @param doc - the document
+ */
+ public MinimalHTMLWriter(Writer w, StyledDocument doc)
+ {
+ super(w, doc);
+ this.doc = doc;
+ tagStack = new ArrayDeque<String>();
+ }
+
+ /**
+ * Constructs a MinimalHTMLWriter.
+ * @param w - a Writer, for output.
+ * @param doc - the document
+ * @param pos - start position
+ * @param len - length
+ */
+ public MinimalHTMLWriter(Writer w, StyledDocument doc, int pos, int len)
+ {
+ super(w, doc, pos, len);
+ this.doc = doc;
+ tagStack = new ArrayDeque<String>();
+ }
+
+ /**
+ * Starts a span tag.
+ */
+ protected void startFontTag(String style) throws IOException
+ {
+ if( inFontTag() )
+ endOpenTags();
+ writeStartTag("<span style=\""+style+"\">");
+ inFontTag = true;
+ }
+
+ /**
+ * Returns whether the writer is within two span tags.
+ */
+ protected boolean inFontTag()
+ {
+ return inFontTag;
+ }
+
+ /**
+ * Ends a span tag.
+ */
+ protected void endFontTag() throws IOException
+ {
+ writeEndTag("</span>");
+ inFontTag = false;
+ }
+
+ /**
+ * Write the entire HTML document.
+ */
+ public synchronized void write() throws IOException, BadLocationException
+ {
+ writeStartTag("<html>");
+ writeHeader();
+ writeBody();
+ writeEndTag("</html>");
+ }
+
+ /**
+ * Write a start tag and increment the indent.
+ */
+ protected void writeStartTag(String tag) throws IOException
+ {
+ indent();
+ write(tag+NEWLINE);
+ incrIndent();
+ }
+
+ /**
+ * Write an ending tag and decrement the indent.
+ */
+ protected void writeEndTag(String endTag) throws IOException
+ {
+ decrIndent();
+ indent();
+ write(endTag+NEWLINE);
+ }
+
+ /**
+ * Write the HTML header.
+ */
+ protected void writeHeader() throws IOException
+ {
+ writeStartTag("<head>");
+ writeStartTag("<style>");
+ writeStartTag("<!--");
+ writeStyles();
+ writeEndTag("-->");
+ writeEndTag("</style>");
+ writeEndTag("</head>");
+ }
+
+ /**
+ * Write a paragraph start tag.
+ */
+ protected void writeStartParagraph(Element elem) throws IOException
+ {
+ indent();
+ write("<p class=default>"+NEWLINE); // FIXME: Class value = ?
+ incrIndent();
+ }
+
+ /**
+ * Write a paragraph end tag, closes any other open tags.
+ */
+ protected void writeEndParagraph() throws IOException
+ {
+ endOpenTags();
+ writeEndTag("</p>");
+ }
+
+ /**
+ * Writes the body of the HTML document.
+ */
+ protected void writeBody() throws IOException, BadLocationException
+ {
+ writeStartTag("<body>");
+
+ ElementIterator ei = getElementIterator();
+ Element e = ei.first();
+ boolean inParagraph = false;
+ do
+ {
+ if( e.isLeaf() )
+ {
+ boolean hasNL = (getText(e).indexOf(NEWLINE) != -1);
+ if( !inParagraph && hasText( e ) )
+ {
+ writeStartParagraph(e);
+ inParagraph = true;
+ }
+
+ if( hasText( e ) )
+ writeContent(e, true);
+
+ if( hasNL && inParagraph )
+ {
+ writeEndParagraph();
+ inParagraph = false;
+ }
+ else
+ endOpenTags();
+ }
+ }
+ while((e = ei.next()) != null);
+
+ writeEndTag("</body>");
+ }
+
+ protected void text(Element elem) throws IOException, BadLocationException
+ {
+ write( getText(elem).trim() );
+ }
+
+ /**
+ * Write bold, indent and underline tags.
+ */
+ protected void writeHTMLTags(AttributeSet attr) throws IOException
+ {
+ if(attr.getAttribute(StyleConstants.Bold) != null)
+ if(((Boolean)attr.getAttribute(StyleConstants.Bold)).booleanValue())
+ {
+ write("<b>");
+ tagStack.push("</b>");
+ }
+ if(attr.getAttribute(StyleConstants.Italic) != null)
+ if(((Boolean)attr.getAttribute(StyleConstants.Italic)).booleanValue())
+ {
+ write("<i>");
+ tagStack.push("</i>");
+ }
+ if(attr.getAttribute(StyleConstants.Underline) != null)
+ if(((Boolean)attr.getAttribute(StyleConstants.Underline)).booleanValue())
+ {
+ write("<u>");
+ tagStack.push("</u>");
+ }
+ }
+
+ /**
+ * Returns whether the element contains text or not.
+ */
+ protected boolean isText(Element elem)
+ {
+ return (elem.getEndOffset() != elem.getStartOffset());
+ }
+
+ /**
+ * Writes the content of an element.
+ */
+ protected void writeContent(Element elem, boolean needsIndenting)
+ throws IOException, BadLocationException
+ {
+ writeNonHTMLAttributes(elem.getAttributes());
+ if(needsIndenting)
+ indent();
+ writeHTMLTags(elem.getAttributes());
+ if( isText(elem) )
+ text(elem);
+ else
+ writeLeaf(elem);
+
+ endOpenTags();
+ }
+
+ /**
+ * Writes a non-text leaf element.
+ */
+ protected void writeLeaf(Element e) throws IOException
+ {
+ // NOTE: Haven't tested if this is correct.
+ if(e.getName().equals(StyleConstants.IconElementName))
+ writeImage(e);
+ else
+ writeComponent(e);
+ }
+
+ /**
+ * Write the HTML attributes which do not have tag equivalents,
+ * e.g. attributes other than bold/italic/underlined.
+ */
+ protected void writeNonHTMLAttributes(AttributeSet attr) throws IOException
+ {
+ String style = "";
+
+ // Alignment? Background?
+
+ if( StyleConstants.getForeground(attr) != null )
+ style = style + "color: " +
+ getColor(StyleConstants.getForeground(attr)) + "; ";
+
+ style = style + "font-size: "+StyleConstants.getFontSize(attr)+"pt; ";
+ style = style + "font-family: "+StyleConstants.getFontFamily(attr);
+
+ startFontTag(style);
+ }
+
+ /**
+ * Write the styles used.
+ */
+ protected void writeStyles() throws IOException
+ {
+ if(doc instanceof DefaultStyledDocument)
+ {
+ Enumeration<?> styles = ((DefaultStyledDocument)doc).getStyleNames();
+ while(styles.hasMoreElements())
+ writeStyle(doc.getStyle((String)styles.nextElement()));
+ }
+ else
+ { // What else to do here?
+ Style s = doc.getStyle("default");
+ if(s != null)
+ writeStyle( s );
+ }
+ }
+
+ /**
+ * Write a set of attributes.
+ */
+ protected void writeAttributes(AttributeSet attr) throws IOException
+ {
+ Enumeration<?> attribs = attr.getAttributeNames();
+ while(attribs.hasMoreElements())
+ {
+ Object attribName = attribs.nextElement();
+ String name = attribName.toString();
+ String output = getAttribute(name, attr.getAttribute(attribName));
+ if( output != null )
+ {
+ indent();
+ write( output + NEWLINE );
+ }
+ }
+ }
+
+ /**
+ * Deliberately unimplemented, handles component elements.
+ */
+ protected void writeComponent(Element elem) throws IOException
+ {
+ }
+
+ /**
+ * Deliberately unimplemented.
+ * Writes StyleConstants.IconElementName elements.
+ */
+ protected void writeImage(Element elem) throws IOException
+ {
+ }
+
+ // -------------------- Private methods. --------------------------------
+
+ /**
+ * Write a single style attribute
+ */
+ private String getAttribute(String name, Object a) throws IOException
+ {
+ if(name.equals("foreground"))
+ return "foreground:"+getColor((Color)a)+";";
+ if(name.equals("background"))
+ return "background:"+getColor((Color)a)+";";
+ if(name.equals("italic"))
+ return "italic:"+(((Boolean)a).booleanValue() ? "italic;" : ";");
+ if(name.equals("bold"))
+ return "bold:"+(((Boolean)a).booleanValue() ? "bold;" : "normal;");
+ if(name.equals("family"))
+ return "family:" + a + ";";
+ if(name.equals("size"))
+ {
+ int size = ((Integer)a).intValue();
+ int htmlSize;
+ if( size > 24 )
+ htmlSize = 7;
+ else if( size > 18 )
+ htmlSize = 6;
+ else if( size > 14 )
+ htmlSize = 5;
+ else if( size > 12 )
+ htmlSize = 4;
+ else if( size > 10 )
+ htmlSize = 3;
+ else if( size > 8 )
+ htmlSize = 2;
+ else
+ htmlSize = 1;
+
+ return "size:" + htmlSize + ";";
+ }
+
+ return null;
+ }
+
+ /**
+ * Stupid that Color doesn't have a method for this.
+ */
+ private String getColor(Color c)
+ {
+ String r = "00" + Integer.toHexString(c.getRed());
+ r = r.substring(r.length() - 2);
+ String g = "00" + Integer.toHexString(c.getGreen());
+ g = g.substring(g.length() - 2);
+ String b = "00" + Integer.toHexString(c.getBlue());
+ b = b.substring(b.length() - 2);
+ return "#" + r + g + b;
+ }
+
+ /**
+ * Empty the stack of open tags
+ */
+ private void endOpenTags() throws IOException
+ {
+ while(tagStack.size() > 0)
+ write(tagStack.pop());
+
+ if( inFontTag() )
+ {
+ write(""+NEWLINE);
+ endFontTag();
+ }
+ }
+
+ /**
+ * Output a single style
+ */
+ private void writeStyle(Style s) throws IOException
+ {
+ if( s == null )
+ return;
+
+ writeStartTag("p."+s.getName()+" {");
+ writeAttributes(s);
+ writeEndTag("}");
+ }
+
+ private boolean hasText(Element e) throws BadLocationException
+ {
+ return (getText(e).trim().length() > 0);
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/MultiAttributeSet.java b/libjava/classpath/javax/swing/text/html/MultiAttributeSet.java
new file mode 100644
index 000000000..e7fa9f373
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/MultiAttributeSet.java
@@ -0,0 +1,213 @@
+/* MultiAttributeSet.java -- Multiplexes between a set of AttributeSets
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+import javax.swing.text.AttributeSet;
+import javax.swing.text.SimpleAttributeSet;
+
+/**
+ * An AttributeSet impl that multiplexes between a set of other AttributeSets.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+class MultiAttributeSet
+ implements AttributeSet
+{
+
+ /**
+ * The Enumeration for the multiplexed names.
+ */
+ private class MultiNameEnumeration
+ implements Enumeration<Object>
+ {
+ /**
+ * The index of the current AttributeSet.
+ */
+ private int index;
+
+ /**
+ * The names Enumeration of the current AttributeSet.
+ */
+ private Enumeration<?> current;
+
+ /**
+ * Creates a new instance.
+ */
+ MultiNameEnumeration()
+ {
+ index = 0;
+ current = multi[0].getAttributeNames();
+ }
+
+ public boolean hasMoreElements()
+ {
+ return current.hasMoreElements() || index < multi.length - 1;
+ }
+
+ public Object nextElement()
+ {
+ if (! current.hasMoreElements())
+ {
+ if (index < multi.length - 1)
+ {
+ index++;
+ current = multi[index].getAttributeNames();
+ }
+ else
+ throw new NoSuchElementException();
+ }
+ return current.nextElement();
+ }
+
+ }
+
+ /**
+ * The AttributeSets to multiplex.
+ */
+ AttributeSet[] multi;
+
+ /**
+ * Provided for subclasses that need to initialize via {@link #init}.
+ */
+ MultiAttributeSet()
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * @param m the AttributeSets to multiplex
+ */
+ MultiAttributeSet(AttributeSet[] m)
+ {
+ init(m);
+ }
+
+ /**
+ * Provided for subclasses to initialize the attribute set.
+ *
+ * @param m the attributes to multiplex
+ */
+ void init(AttributeSet[] m)
+ {
+ multi = m;
+ }
+
+ public boolean containsAttribute(Object name, Object value)
+ {
+ boolean ret = false;
+ for (int i = 0; i < multi.length && ret == false; i++)
+ {
+ if (multi[i].containsAttribute(name, value))
+ ret = true;
+ }
+ return ret;
+ }
+
+ public boolean containsAttributes(AttributeSet attributes)
+ {
+ boolean ret = true;
+ Enumeration<?> e = attributes.getAttributeNames();
+ while (ret && e.hasMoreElements())
+ {
+ Object key = e.nextElement();
+ ret = attributes.getAttribute(key).equals(getAttribute(key));
+ }
+ return ret;
+ }
+
+ public AttributeSet copyAttributes()
+ {
+ SimpleAttributeSet copy = new SimpleAttributeSet();
+ for (int i = 0; i < multi.length; i++)
+ {
+ copy.addAttributes(multi[i]);
+ }
+ return copy;
+ }
+
+ public Object getAttribute(Object key)
+ {
+ Object ret = null;
+ for (int i = 0; i < multi.length && ret == null; i++)
+ {
+ ret = multi[i].getAttribute(key);
+ }
+ return ret;
+ }
+
+ public int getAttributeCount()
+ {
+ int n = 0;
+ for (int i = 0; i < multi.length; i++)
+ {
+ n += multi[i].getAttributeCount();
+ }
+ return n;
+ }
+
+ public Enumeration<?> getAttributeNames()
+ {
+ return new MultiNameEnumeration();
+ }
+
+ public AttributeSet getResolveParent()
+ {
+ return null;
+ }
+
+ public boolean isDefined(Object attrName)
+ {
+ boolean ret = false;
+ for (int i = 0; i < multi.length && ! ret; i++)
+ ret = multi[i].isDefined(attrName);
+ return ret;
+ }
+
+ public boolean isEqual(AttributeSet attr)
+ {
+ return getAttributeCount() == attr.getAttributeCount()
+ && containsAttributes(attr);
+ }
+
+}
diff --git a/libjava/classpath/javax/swing/text/html/MultiStyle.java b/libjava/classpath/javax/swing/text/html/MultiStyle.java
new file mode 100644
index 000000000..eb6215035
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/MultiStyle.java
@@ -0,0 +1,136 @@
+/* MultiStyle.java -- Multiplexes between several Styles
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import java.util.Enumeration;
+
+import javax.swing.event.ChangeListener;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.Style;
+
+/**
+ * A Style implementation that is able to multiplex between several other
+ * Styles. This is used for CSS style resolving.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+class MultiStyle
+ extends MultiAttributeSet
+ implements Style
+{
+
+ // FIXME: Fix the implementation to also return attributes that
+ // are added to this style, etc. However, this is not really needed
+ // now for CSS, but would be nice for correctness.
+
+ /**
+ * The name of the style.
+ */
+ private String name;
+
+ /**
+ * The attributes added to this style.
+ */
+ private SimpleAttributeSet attributes;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param n the name
+ * @param m the styles to multiplex
+ */
+ public MultiStyle(String n, AttributeSet[] m)
+ {
+ super(m);
+ name = n;
+ attributes = new SimpleAttributeSet();
+ }
+
+ /**
+ * Returns the name of the style.
+ *
+ * @return the name of the style
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ public void addChangeListener(ChangeListener listener)
+ {
+ // TODO: Implement.
+ }
+
+ public void removeChangeListener(ChangeListener listener)
+ {
+ // TODO: Implement.
+ }
+
+ public void addAttribute(Object name, Object value)
+ {
+ attributes.addAttribute(name, value);
+ }
+
+ public void addAttributes(AttributeSet atts)
+ {
+ attributes.addAttributes(atts);
+ }
+
+ public void removeAttribute(Object name)
+ {
+ attributes.removeAttribute(name);
+ }
+
+ public void removeAttributes(Enumeration<?> names)
+ {
+ attributes.removeAttribute(names);
+ }
+
+ public void removeAttributes(AttributeSet atts)
+ {
+ attributes.removeAttribute(atts);
+ }
+
+ public void setResolveParent(AttributeSet parent)
+ {
+ // TODO: Implement.
+ }
+
+}
diff --git a/libjava/classpath/javax/swing/text/html/NullView.java b/libjava/classpath/javax/swing/text/html/NullView.java
new file mode 100644
index 000000000..86ce0c10f
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/NullView.java
@@ -0,0 +1,102 @@
+/* NullView.java -- A dummy view that renders nothing
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import java.awt.Graphics;
+import java.awt.Shape;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Element;
+import javax.swing.text.View;
+import javax.swing.text.Position.Bias;
+
+/**
+ * A dummy view that renders nothing. This is used for invisible HTML elements
+ * like <head>.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+class NullView
+ extends View
+{
+
+ /**
+ * Creates a new NullView.
+ *
+ * @param elem the element
+ */
+ public NullView(Element elem)
+ {
+ super(elem);
+ }
+
+ /**
+ * Does nothing.
+ */
+ public void paint(Graphics g, Shape s)
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Returns zero for both directions.
+ */
+ public float getPreferredSpan(int axis)
+ {
+ return 0;
+ }
+
+ /**
+ * Returns the allocation of this view, which should be empty anyway.
+ */
+ public Shape modelToView(int pos, Shape a, Bias b)
+ throws BadLocationException
+ {
+ return a;
+ }
+
+ /**
+ * Returns the start offset of the element.
+ */
+ public int viewToModel(float x, float y, Shape a, Bias[] b)
+ {
+ return getElement().getStartOffset();
+ }
+
+}
diff --git a/libjava/classpath/javax/swing/text/html/ObjectView.java b/libjava/classpath/javax/swing/text/html/ObjectView.java
new file mode 100644
index 000000000..9d900441b
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/ObjectView.java
@@ -0,0 +1,110 @@
+/* ObjectView.java -- A view for HTML object tags
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import java.awt.Component;
+
+import javax.swing.text.AttributeSet;
+import javax.swing.text.ComponentView;
+import javax.swing.text.Element;
+
+/**
+ * A view for HTML <code>&lt;object&gt;</code> tags.
+ *
+ * This is a {@link ComponentView} that creates special components depending
+ * on the object specification. If the object tag has a classid attribute, then
+ * this view will try to load the class specified by this attribute using the
+ * classloader that loaded the associated document. If the class could be
+ * loaded, an instance is created and the type narrowed to {@link Component}.
+ *
+ * It is also possible to set bean properties on the created component using
+ * nested <code>&lt;param&gt;</code> tags. For example:
+ * <pre>
+ * <object classid="javax.swing.JLabel">
+ * <param name="text" value="sample text">
+ * </object>
+ * </pre>
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class ObjectView extends ComponentView
+{
+
+ /**
+ * Creates a new <code>ObjectView</code>.
+ *
+ * @param el the element for which to create a view
+ */
+ public ObjectView(Element el)
+ {
+ super(el);
+ }
+
+ /**
+ * Creates a component based on the specification in the element of this
+ * view. See the class description for details.
+ */
+ protected Component createComponent()
+ {
+ Component comp = null;
+ Element el = getElement();
+ AttributeSet atts = el.getAttributes();
+ String classId = (String) atts.getAttribute("classid");
+ try
+ {
+ Class<?> objectClass = Class.forName(classId);
+ Object instance = objectClass.newInstance();
+ comp = (Component) instance;
+ }
+ catch (ClassNotFoundException ex)
+ {
+ // Ignored.
+ }
+ catch (IllegalAccessException ex)
+ {
+ // Ignored.
+ }
+ catch (InstantiationException ex)
+ {
+ // Ignored.
+ }
+ // FIXME: Handle param tags and set bean properties accordingly.
+ return comp;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/Option.java b/libjava/classpath/javax/swing/text/html/Option.java
new file mode 100644
index 000000000..18d5c2bd8
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/Option.java
@@ -0,0 +1,159 @@
+/* Option.java -- Value class for <option> list model elements
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import javax.swing.text.AttributeSet;
+
+/**
+ * Value class for the combobox model that renders <code>&lt;option&gt;</code>
+ * elements.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class Option
+{
+
+ /**
+ * The attributes of the <option> tag.
+ */
+ private AttributeSet attributes;
+
+ /**
+ * The label.
+ */
+ private String label;
+
+ /**
+ * The selected state of this label.
+ */
+ private boolean selected;
+
+ /**
+ * Creates a new <code>Option</code> instance that uses the specified
+ * tag attributes.
+ *
+ * @param attr the attributes to use
+ */
+ public Option(AttributeSet attr)
+ {
+ // Protect the attribute set.
+ attributes = attr.copyAttributes();
+ label = null;
+ selected = attr.getAttribute(HTML.Attribute.SELECTED) != null;
+ }
+
+ /**
+ * Sets the label to use for this <code>&lt;option&gt;</code> tag.
+ *
+ * @param l the label to set
+ */
+ public void setLabel(String l)
+ {
+ label = l;
+ }
+
+ /**
+ * Returns the label of this <code>&lt;option&gt;</code> tag.
+ *
+ * @return the label of this <code>&lt;option&gt;</code> tag
+ */
+ public String getLabel()
+ {
+ return label;
+ }
+
+ /**
+ * Returns the attributes used to render this <code>&lt;option&gt;</code>
+ * tag.
+ *
+ * @return the attributes used to render this <code>&lt;option&gt;</code> tag
+ */
+ public AttributeSet getAttributes()
+ {
+ return attributes;
+ }
+
+ /**
+ * Returns a string representation of this <code>&lt;option&gt;</code> tag.
+ * This returns the <code>label</code> property.
+ *
+ * @return a string representation of this <code>&lt;option&gt;</code> tag
+ */
+ public String toString()
+ {
+ return label;
+ }
+
+ /**
+ * Sets the selected state of this <code>&lt;option&gt;</code> tag.
+ *
+ * @param s the selected state to set
+ */
+ protected void setSelection(boolean s)
+ {
+ selected = s;
+ }
+
+ /**
+ * Returns <code>true</code> when this option is selected, <code>false</code>
+ * otherwise.
+ *
+ * @return <code>true</code> when this option is selected, <code>false</code>
+ * otherwise
+ */
+ public boolean isSelected()
+ {
+ return selected;
+ }
+
+ /**
+ * Returns the string associated with the <code>value</code> attribute or
+ * the label, if no such attribute is specified.
+ *
+ * @return the string associated with the <code>value</code> attribute or
+ * the label, if no such attribute is specified
+ */
+ public String getValue()
+ {
+ String value = (String) attributes.getAttribute(HTML.Attribute.VALUE);
+ if (value == null)
+ value = label;
+ return value;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/ParagraphView.java b/libjava/classpath/javax/swing/text/html/ParagraphView.java
new file mode 100644
index 000000000..cab8edb28
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/ParagraphView.java
@@ -0,0 +1,322 @@
+/* ParagraphView.java -- Renders a paragraph in HTML
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import gnu.javax.swing.text.html.css.Length;
+
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+import javax.swing.SizeRequirements;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.View;
+
+/**
+ * Renders a paragraph in HTML. This is a subclass of
+ * {@link javax.swing.text.ParagraphView} with some adjustments for
+ * understanding stylesheets.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public class ParagraphView
+ extends javax.swing.text.ParagraphView
+{
+
+ /**
+ * The attributes used by this view.
+ */
+ private AttributeSet attributes;
+
+ /**
+ * The stylesheet's box painter.
+ */
+ private StyleSheet.BoxPainter painter;
+
+ /**
+ * The width as specified in the stylesheet or null if not specified.
+ */
+ private Length cssWidth;
+
+ /**
+ * The height as specified in the stylesheet or null if not specified.
+ */
+ private Length cssHeight;
+
+ /**
+ * Creates a new ParagraphView for the specified element.
+ *
+ * @param element the element
+ */
+ public ParagraphView(Element element)
+ {
+ super(element);
+ }
+
+ /**
+ * Sets the parent of this view. This is implemented to call the parent
+ * functionality and then trigger {@link #setPropertiesFromAttributes} in
+ * order to load the stylesheet attributes.
+ *
+ * @param parent the parent view to set
+ */
+ public void setParent(View parent)
+ {
+ super.setParent(parent);
+ if (parent != null)
+ setPropertiesFromAttributes();
+ }
+
+ /**
+ * Returns the attributes used by this view. This is implemented to multiplex
+ * the attributes of the model with the attributes of the stylesheet.
+ */
+ public AttributeSet getAttributes()
+ {
+ if (attributes == null)
+ {
+ attributes = getStyleSheet().getViewAttributes(this);
+ }
+ return attributes;
+ }
+
+ /**
+ * Loads the visual properties of the ParagraphView from the element's
+ * attributes and the stylesheet of the HTML document.
+ */
+ protected void setPropertiesFromAttributes()
+ {
+ super.setPropertiesFromAttributes();
+
+ // Fetch CSS attributes.
+ attributes = getAttributes();
+ if (attributes != null)
+ {
+ super.setPropertiesFromAttributes();
+ Object o = attributes.getAttribute(CSS.Attribute.TEXT_ALIGN);
+ if (o != null)
+ {
+ String align = o.toString();
+ if (align.equals("left"))
+ setJustification(StyleConstants.ALIGN_LEFT);
+ else if (align.equals("right"))
+ setJustification(StyleConstants.ALIGN_RIGHT);
+ else if (align.equals("center"))
+ setJustification(StyleConstants.ALIGN_CENTER);
+ else if (align.equals("justify"))
+ setJustification(StyleConstants.ALIGN_JUSTIFIED);
+ }
+
+ // Fetch StyleSheet's box painter.
+ painter = getStyleSheet().getBoxPainter(attributes);
+ setInsets((short) painter.getInset(TOP, this),
+ (short) painter.getInset(LEFT, this),
+ (short) painter.getInset(BOTTOM, this),
+ (short) painter.getInset(RIGHT, this));
+
+ StyleSheet ss = getStyleSheet();
+ float emBase = ss.getEMBase(attributes);
+ float exBase = ss.getEXBase(attributes);
+ cssWidth = (Length) attributes.getAttribute(CSS.Attribute.WIDTH);
+ if (cssWidth != null)
+ cssWidth.setFontBases(emBase, exBase);
+ cssHeight = (Length) attributes.getAttribute(CSS.Attribute.WIDTH);
+ if (cssHeight != null)
+ cssHeight.setFontBases(emBase, exBase);
+ }
+ }
+
+ /**
+ * Returns the stylesheet used by this view.
+ *
+ * @return the stylesheet used by this view
+ */
+ protected StyleSheet getStyleSheet()
+ {
+ Document doc = getDocument();
+ StyleSheet styleSheet = null;
+ if (doc instanceof HTMLDocument)
+ styleSheet = ((HTMLDocument) doc).getStyleSheet();
+ return styleSheet;
+ }
+
+ /**
+ * Calculates the minor axis requirements of this view. This is implemented
+ * to return the super class'es requirements and modifies the minimumSpan
+ * slightly so that it is not smaller than the length of the longest word.
+ *
+ * @param axis the axis
+ * @param r the SizeRequirements object to be used as return parameter;
+ * if <code>null</code> a new one will be created
+ *
+ * @return the requirements along the minor layout axis
+ */
+ protected SizeRequirements calculateMinorAxisRequirements(int axis,
+ SizeRequirements r)
+ {
+ r = super.calculateMinorAxisRequirements(axis, r);
+ if (! setCSSSpan(r, axis))
+ {
+ int margin = axis == X_AXIS ? getLeftInset() + getRightInset()
+ : getTopInset() + getBottomInset();
+ r.minimum -= margin;
+ r.preferred -= margin;
+ r.maximum -= margin;
+ }
+ return r;
+ }
+
+ /**
+ * Sets the span on the SizeRequirements object according to the
+ * according CSS span value, when it is set.
+ *
+ * @param r the size requirements
+ * @param axis the axis
+ *
+ * @return <code>true</code> when the CSS span has been set,
+ * <code>false</code> otherwise
+ */
+ private boolean setCSSSpan(SizeRequirements r, int axis)
+ {
+ boolean ret = false;
+ if (axis == X_AXIS)
+ {
+ if (cssWidth != null && ! cssWidth.isPercentage())
+ {
+ r.minimum = (int) cssWidth.getValue();
+ r.preferred = (int) cssWidth.getValue();
+ r.maximum = (int) cssWidth.getValue();
+ ret = true;
+ }
+ }
+ else
+ {
+ if (cssHeight != null && ! cssWidth.isPercentage())
+ {
+ r.minimum = (int) cssHeight.getValue();
+ r.preferred = (int) cssHeight.getValue();
+ r.maximum = (int) cssHeight.getValue();
+ ret = true;
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Determines if this view is visible or not. If none of the children is
+ * visible and the only visible child is the break that ends the paragraph,
+ * this paragraph is not considered to be visible.
+ *
+ * @return the visibility of this paragraph
+ */
+ public boolean isVisible()
+ {
+ // FIXME: Implement the above specified behaviour.
+ return super.isVisible();
+ }
+
+ /**
+ * Paints this view. This paints the box using the stylesheet's
+ * box painter for this view and delegates to the super class paint()
+ * afterwards.
+ *
+ * @param g the graphics object
+ * @param a the current allocation of this view
+ */
+ public void paint(Graphics g, Shape a)
+ {
+ if (a != null)
+ {
+ Rectangle r = a instanceof Rectangle ? (Rectangle) a : a.getBounds();
+ painter.paint(g, r.x, r.y, r.width, r.height, this);
+ }
+ super.paint(g, a);
+ }
+
+ /**
+ * Returns the preferred span of this view. If this view is not visible,
+ * we return <code>0</code>, otherwise the super class is called.
+ *
+ * @param axis the axis
+ *
+ * @return the preferred span of this view
+ */
+ public float getPreferredSpan(int axis)
+ {
+ float span = 0;
+ if (isVisible())
+ span = super.getPreferredSpan(axis);
+ return span;
+ }
+
+ /**
+ * Returns the minimum span of this view. If this view is not visible,
+ * we return <code>0</code>, otherwise the super class is called.
+ *
+ * @param axis the axis
+ *
+ * @return the minimum span of this view
+ */
+ public float getMinimumSpan(int axis)
+ {
+ float span = 0;
+ if (isVisible())
+ span = super.getMinimumSpan(axis);
+ return span;
+ }
+
+ /**
+ * Returns the maximum span of this view. If this view is not visible,
+ * we return <code>0</code>, otherwise the super class is called.
+ *
+ * @param axis the axis
+ *
+ * @return the maximum span of this view
+ */
+ public float getMaximumSpan(int axis)
+ {
+ float span = 0;
+ if (isVisible())
+ span = super.getMaximumSpan(axis);
+ return span;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/ResetableModel.java b/libjava/classpath/javax/swing/text/html/ResetableModel.java
new file mode 100644
index 000000000..17f65b97d
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/ResetableModel.java
@@ -0,0 +1,50 @@
+/* ResetableModel.java -- Form models that can be resetted
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+/**
+ * Form models that can be resetted implement this.
+ */
+interface ResetableModel
+{
+ /**
+ * Resets the model.
+ */
+ void reset();
+}
diff --git a/libjava/classpath/javax/swing/text/html/ResetablePlainDocument.java b/libjava/classpath/javax/swing/text/html/ResetablePlainDocument.java
new file mode 100644
index 000000000..6177f9b86
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/ResetablePlainDocument.java
@@ -0,0 +1,82 @@
+/* ResetablePlainDocument.java -- A plain document for use in the HTML renderer
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.PlainDocument;
+
+/**
+ * A PlainDocument that can be resetted.
+ */
+class ResetablePlainDocument
+ extends PlainDocument
+ implements ResetableModel
+{
+ /**
+ * The initial text.
+ */
+ private String initial;
+
+ /**
+ * Stores the initial text.
+ *
+ * @param text the initial text
+ */
+ void setInitialText(String text)
+ {
+ initial = text;
+ }
+
+ /**
+ * Resets the model.
+ */
+ public void reset()
+ {
+ try
+ {
+ replace(0, getLength(), initial, null);
+ }
+ catch (BadLocationException ex)
+ {
+ // Shouldn't happen.
+ assert false;
+ }
+ }
+
+}
diff --git a/libjava/classpath/javax/swing/text/html/ResetableToggleButtonModel.java b/libjava/classpath/javax/swing/text/html/ResetableToggleButtonModel.java
new file mode 100644
index 000000000..637ece151
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/ResetableToggleButtonModel.java
@@ -0,0 +1,70 @@
+/* ResetableToggleButtonModel.java -- A toggle button model with reset support
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import javax.swing.JToggleButton.ToggleButtonModel;
+
+class ResetableToggleButtonModel
+ extends ToggleButtonModel
+ implements ResetableModel
+{
+
+ /**
+ * The initial state.
+ */
+ private boolean initial;
+
+ /**
+ * Sets the initial selection value.
+ *
+ * @param state the initial value
+ */
+ public void setInitial(boolean state)
+ {
+ initial = state;
+ }
+
+ /**
+ * Resets the model.
+ */
+ public void reset()
+ {
+ setSelected(initial);
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/SelectComboBoxModel.java b/libjava/classpath/javax/swing/text/html/SelectComboBoxModel.java
new file mode 100644
index 000000000..999746413
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/SelectComboBoxModel.java
@@ -0,0 +1,84 @@
+/* SelectComboBoxModel.java -- A special ComboBoxModel for use in HTML renderer
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import javax.swing.DefaultComboBoxModel;
+
+/**
+ * A special ComboBoxModel that supports storing the initial value so that
+ * the combobox can be resetted later.
+ */
+class SelectComboBoxModel
+ extends DefaultComboBoxModel
+ implements ResetableModel
+{
+
+ /**
+ * The initial selection.
+ */
+ private Option initial;
+
+ /**
+ * Sets the initial selection.
+ *
+ * @param option the initial selection
+ */
+ void setInitialSelection(Option option)
+ {
+ initial = option;
+ }
+
+ /**
+ * Returns the initial selection.
+ *
+ * @return the initial selection
+ */
+ Option getInitialSelection()
+ {
+ return initial;
+ }
+
+ /**
+ * Resets the model.
+ */
+ public void reset()
+ {
+ setSelectedItem(initial);
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/SelectListModel.java b/libjava/classpath/javax/swing/text/html/SelectListModel.java
new file mode 100644
index 000000000..23bfaa11b
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/SelectListModel.java
@@ -0,0 +1,106 @@
+/* OptionListModel.java -- A special ListModel for use in the HTML renderer
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import java.util.BitSet;
+
+import javax.swing.DefaultListModel;
+import javax.swing.DefaultListSelectionModel;
+import javax.swing.ListSelectionModel;
+
+/**
+ * A special list model that encapsulates its selection model and supports
+ * storing of the initial value so that it can be resetted.
+ */
+class SelectListModel
+ extends DefaultListModel
+ implements ResetableModel
+{
+ /**
+ * The selection model.
+ */
+ private DefaultListSelectionModel selectionModel;
+
+ /**
+ * The initial selection.
+ */
+ private BitSet initialSelection;
+
+ /**
+ * Creates a new SelectListModel.
+ */
+ SelectListModel()
+ {
+ selectionModel = new DefaultListSelectionModel();
+ initialSelection = new BitSet();
+ }
+
+ /**
+ * Sets the initial selection.
+ *
+ * @param init the initial selection
+ */
+ void addInitialSelection(int init)
+ {
+ initialSelection.set(init);
+ }
+
+ /**
+ * Resets the model.
+ */
+ public void reset()
+ {
+ selectionModel.clearSelection();
+ for (int i = initialSelection.size(); i >= 0; i--)
+ {
+ if (initialSelection.get(i))
+ selectionModel.addSelectionInterval(i, i);
+ }
+ }
+
+ /**
+ * Returns the associated selection model.
+ *
+ * @return the associated selection model
+ */
+ ListSelectionModel getSelectionModel()
+ {
+ return selectionModel;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/StyleSheet.java b/libjava/classpath/javax/swing/text/html/StyleSheet.java
new file mode 100644
index 000000000..5cf015bc5
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/StyleSheet.java
@@ -0,0 +1,1455 @@
+/* StyleSheet.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 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.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.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.font.FontRenderContext;
+import java.awt.geom.Rectangle2D;
+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 java.util.Map;
+
+import javax.swing.border.Border;
+import javax.swing.event.ChangeListener;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.Element;
+import javax.swing.text.MutableAttributeSet;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.Style;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.StyleContext;
+import javax.swing.text.View;
+
+
+/**
+ * This class adds support for defining the visual characteristics of HTML views
+ * being rendered. This enables views to be customized by a look-and-feel, mulitple
+ * views over the same model can be rendered differently. Each EditorPane has its
+ * own StyleSheet, but by default one sheet will be shared by all of the HTMLEditorKit
+ * instances. An HTMLDocument can also have a StyleSheet, which holds specific CSS
+ * specs.
+ *
+ * In order for Views to store less state and therefore be more lightweight,
+ * the StyleSheet can act as a factory for painters that handle some of the
+ * rendering tasks. Since the StyleSheet may be used by views over multiple
+ * documents the HTML attributes don't effect the selector being used.
+ *
+ * The rules are stored as named styles, and other information is stored to
+ * translate the context of an element to a rule.
+ *
+ * @author Lillian Angel (langel@redhat.com)
+ */
+public class StyleSheet extends StyleContext
+{
+
+ /**
+ * Parses CSS stylesheets using the parser in gnu/javax/swing/html/css.
+ *
+ * This is package private to avoid accessor methods.
+ */
+ class CSSStyleSheetParserCallback
+ implements CSSParserCallback
+ {
+ /**
+ * The current styles.
+ */
+ private CSSStyle[] styles;
+
+ /**
+ * The precedence of the stylesheet to be parsed.
+ */
+ private int precedence;
+
+ /**
+ * Creates a new CSS parser. This parser parses a CSS stylesheet with
+ * the specified precedence.
+ *
+ * @param prec the precedence, according to the constants defined in
+ * CSSStyle
+ */
+ CSSStyleSheetParserCallback(int prec)
+ {
+ precedence = prec;
+ }
+
+ /**
+ * Called at the beginning of a statement.
+ *
+ * @param sel the selector
+ */
+ public void startStatement(Selector[] sel)
+ {
+ styles = new CSSStyle[sel.length];
+ for (int i = 0; i < sel.length; i++)
+ styles[i] = new CSSStyle(precedence, sel[i]);
+ }
+
+ /**
+ * Called at the end of a statement.
+ */
+ public void endStatement()
+ {
+ for (int i = 0; i < styles.length; i++)
+ css.add(styles[i]);
+ styles = 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);
+ for (int i = 0; i < styles.length; i++)
+ {
+ CSSStyle style = styles[i];
+ 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<CSSStyle>
+ {
+
+ static final int PREC_UA = 0;
+ static final int PREC_NORM = 100000;
+ static final int PREC_AUTHOR_NORMAL = 200000;
+ static final int PREC_AUTHOR_IMPORTANT = 300000;
+ static final int PREC_USER_IMPORTANT = 400000;
+
+ /**
+ * The priority of this style when matching CSS selectors.
+ */
+ private int precedence;
+
+ /**
+ * The selector for this rule.
+ *
+ * This is package private to avoid accessor methods.
+ */
+ Selector selector;
+
+ CSSStyle(int prec, Selector sel)
+ {
+ precedence = prec;
+ selector = sel;
+ }
+
+ public String getName()
+ {
+ // TODO: Implement this for correctness.
+ return null;
+ }
+
+ public void addChangeListener(ChangeListener listener)
+ {
+ // TODO: Implement this for correctness.
+ }
+
+ public void removeChangeListener(ChangeListener listener)
+ {
+ // TODO: Implement this for correctness.
+ }
+
+ /**
+ * Sorts the rule according to the style's precedence and the
+ * selectors specificity.
+ */
+ public int compareTo(CSSStyle other)
+ {
+ return other.precedence + other.selector.getSpecificity()
+ - precedence - selector.getSpecificity();
+ }
+
+ }
+
+ /** The base URL */
+ URL base;
+
+ /** Base font size (int) */
+ int baseFontSize;
+
+ /**
+ * The linked style sheets stored.
+ */
+ private ArrayList<StyleSheet> linked;
+
+ /**
+ * Maps element names (selectors) to AttributSet (the corresponding style
+ * information).
+ */
+ ArrayList<CSSStyle> css = new ArrayList<CSSStyle>();
+
+ /**
+ * Maps selectors to their resolved styles.
+ */
+ private HashMap<String,Style> resolvedStyles;
+
+ /**
+ * Constructs a StyleSheet.
+ */
+ public StyleSheet()
+ {
+ super();
+ baseFontSize = 4; // Default font size from CSS
+ resolvedStyles = new HashMap<String,Style>();
+ }
+
+ /**
+ * Gets the style used to render the given tag. The element represents the tag
+ * and can be used to determine the nesting, where the attributes will differ
+ * if there is nesting inside of elements.
+ *
+ * @param t - the tag to translate to visual attributes
+ * @param e - the element representing the tag
+ * @return the set of CSS attributes to use to render the tag.
+ */
+ public Style getRule(HTML.Tag t, Element e)
+ {
+ // Create list of the element and all of its parents, starting
+ // with the bottommost element.
+ ArrayList<Element> path = new ArrayList<Element>();
+ Element el;
+ AttributeSet atts;
+ for (el = e; el != null; el = el.getParentElement())
+ path.add(el);
+
+ // Create fully qualified selector.
+ StringBuilder selector = new StringBuilder();
+ int count = path.size();
+ // We append the actual element after this loop.
+ for (int i = count - 1; i > 0; i--)
+ {
+ el = path.get(i);
+ atts = el.getAttributes();
+ Object name = atts.getAttribute(StyleConstants.NameAttribute);
+ selector.append(name.toString());
+ if (atts.isDefined(HTML.Attribute.ID))
+ {
+ selector.append('#');
+ selector.append(atts.getAttribute(HTML.Attribute.ID));
+ }
+ if (atts.isDefined(HTML.Attribute.CLASS))
+ {
+ selector.append('.');
+ selector.append(atts.getAttribute(HTML.Attribute.CLASS));
+ }
+ if (atts.isDefined(HTML.Attribute.DYNAMIC_CLASS))
+ {
+ selector.append(':');
+ selector.append(atts.getAttribute(HTML.Attribute.DYNAMIC_CLASS));
+ }
+ if (atts.isDefined(HTML.Attribute.PSEUDO_CLASS))
+ {
+ selector.append(':');
+ selector.append(atts.getAttribute(HTML.Attribute.PSEUDO_CLASS));
+ }
+ selector.append(' ');
+ }
+ selector.append(t.toString());
+ el = path.get(0);
+ atts = el.getAttributes();
+ // For leaf elements, we have to fetch the tag specific attributes.
+ if (el.isLeaf())
+ {
+ Object o = atts.getAttribute(t);
+ if (o instanceof AttributeSet)
+ atts = (AttributeSet) o;
+ else
+ atts = null;
+ }
+ if (atts != null)
+ {
+ if (atts.isDefined(HTML.Attribute.ID))
+ {
+ selector.append('#');
+ selector.append(atts.getAttribute(HTML.Attribute.ID));
+ }
+ if (atts.isDefined(HTML.Attribute.CLASS))
+ {
+ selector.append('.');
+ selector.append(atts.getAttribute(HTML.Attribute.CLASS));
+ }
+ if (atts.isDefined(HTML.Attribute.DYNAMIC_CLASS))
+ {
+ selector.append(':');
+ selector.append(atts.getAttribute(HTML.Attribute.DYNAMIC_CLASS));
+ }
+ if (atts.isDefined(HTML.Attribute.PSEUDO_CLASS))
+ {
+ selector.append(':');
+ selector.append(atts.getAttribute(HTML.Attribute.PSEUDO_CLASS));
+ }
+ }
+ return getResolvedStyle(selector.toString(), path, t);
+ }
+
+ /**
+ * Fetches a resolved style. If there is no resolved style for the
+ * specified selector, the resolve the style using
+ * {@link #resolveStyle(String, List, HTML.Tag)}.
+ *
+ * @param selector the selector for which to resolve the style
+ * @param path the Element path, used in the resolving algorithm
+ * @param tag the tag for which to resolve
+ *
+ * @return the resolved style
+ */
+ private Style getResolvedStyle(String selector, List<Element> path, HTML.Tag tag)
+ {
+ Style style = resolvedStyles.get(selector);
+ if (style == null)
+ style = resolveStyle(selector, path, tag);
+ return style;
+ }
+
+ /**
+ * Resolves a style. This creates arrays that hold the tag names,
+ * class and id attributes and delegates the work to
+ * {@link #resolveStyle(String, String[], List<Map<String,String>>)}.
+ *
+ * @param selector the selector
+ * @param path the Element path
+ * @param tag the tag
+ *
+ * @return the resolved style
+ */
+ private Style resolveStyle(String selector, List<Element> path, HTML.Tag tag)
+ {
+ int count = path.size();
+ String[] tags = new String[count];
+ List<Map<String,String>> attributes =
+ new ArrayList<Map<String,String>>(count);
+ for (int i = 0; i < count; i++)
+ {
+ Element el = path.get(i);
+ AttributeSet atts = el.getAttributes();
+ if (i == 0 && el.isLeaf())
+ {
+ Object o = atts.getAttribute(tag);
+ if (o instanceof AttributeSet)
+ atts = (AttributeSet) o;
+ else
+ atts = null;
+ }
+ if (atts != null)
+ {
+ HTML.Tag t =
+ (HTML.Tag) atts.getAttribute(StyleConstants.NameAttribute);
+ if (t != null)
+ tags[i] = t.toString();
+ else
+ tags[i] = null;
+ attributes.set(i, attributeSetToMap(atts));
+ }
+ else
+ {
+ tags[i] = null;
+ }
+ }
+ tags[0] = tag.toString();
+ return resolveStyle(selector, tags, attributes);
+ }
+
+ /**
+ * Performs style resolving.
+ *
+ * @param selector the selector
+ * @param tags the tags
+ * @param attributes the attributes of the tags
+ *
+ * @return the resolved style
+ */
+ private Style resolveStyle(String selector, String[] tags,
+ List<Map<String,String>> attributes)
+ {
+ // FIXME: This style resolver is not correct. But it works good enough for
+ // the default.css.
+ ArrayList<CSSStyle> styles = new ArrayList<CSSStyle>();
+ for (CSSStyle style : css)
+ {
+ if (style.selector.matches(tags, attributes))
+ styles.add(style);
+ }
+
+ // Add styles from linked stylesheets.
+ if (linked != null)
+ {
+ for (int i = linked.size() - 1; i >= 0; i--)
+ {
+ StyleSheet ss = linked.get(i);
+ for (int j = ss.css.size() - 1; j >= 0; j--)
+ {
+ CSSStyle style = ss.css.get(j);
+ if (style.selector.matches(tags, attributes))
+ styles.add(style);
+ }
+ }
+ }
+
+ // Sort selectors.
+ Collections.sort(styles);
+ Style[] styleArray = styles.toArray(new Style[styles.size()]);
+ Style resolved = new MultiStyle(selector, styleArray);
+ resolvedStyles.put(selector, resolved);
+ return resolved;
+ }
+
+ /**
+ * Gets the rule that best matches the selector. selector is a space
+ * separated String of element names. The attributes of the returned
+ * Style will change as rules are added and removed.
+ *
+ * @param selector - the element names separated by spaces
+ * @return the set of CSS attributes to use to render
+ */
+ public Style getRule(String selector)
+ {
+ CSSStyle best = null;
+ for (Iterator<CSSStyle> i = css.iterator(); i.hasNext();)
+ {
+ CSSStyle style = i.next();
+ if (style.compareTo(best) < 0)
+ best = style;
+ }
+ return best;
+ }
+
+ /**
+ * Adds a set of rules to the sheet. The rules are expected to be in valid
+ * CSS format. This is called as a result of parsing a <style> tag
+ *
+ * @param rule - the rule to add to the sheet
+ */
+ public void addRule(String rule)
+ {
+ CSSStyleSheetParserCallback cb =
+ new CSSStyleSheetParserCallback(CSSStyle.PREC_AUTHOR_NORMAL);
+ // FIXME: Handle ref.
+ StringReader in = new StringReader(rule);
+ CSSParser parser = new CSSParser(in, cb);
+ try
+ {
+ parser.parse();
+ }
+ catch (IOException ex)
+ {
+ // Shouldn't happen. And if, then don't let it bork the outside code.
+ }
+ // Clean up resolved styles cache so that the new styles are recognized
+ // on next stylesheet request.
+ resolvedStyles.clear();
+ }
+
+ /**
+ * Translates a CSS declaration into an AttributeSet. This is called
+ * as a result of encountering an HTML style attribute.
+ *
+ * @param decl - the declaration to get
+ * @return the AttributeSet representing the declaration
+ */
+ public AttributeSet getDeclaration(String decl)
+ {
+ if (decl == null)
+ return SimpleAttributeSet.EMPTY;
+ // FIXME: Not implemented.
+ return null;
+ }
+
+ /**
+ * Loads a set of rules that have been specified in terms of CSS grammar.
+ * If there are any conflicts with existing rules, the new rule is added.
+ *
+ * @param in - the stream to read the CSS grammar from.
+ * @param ref - the reference URL. It is the location of the stream, it may
+ * be null. All relative URLs specified in the stream will be based upon this
+ * parameter.
+ * @throws IOException - For any IO error while reading
+ */
+ public void loadRules(Reader in, URL ref)
+ throws IOException
+ {
+ CSSStyleSheetParserCallback cb =
+ new CSSStyleSheetParserCallback(CSSStyle.PREC_UA);
+ // FIXME: Handle ref.
+ CSSParser parser = new CSSParser(in, cb);
+ parser.parse();
+ }
+
+ /**
+ * Gets a set of attributes to use in the view. This is a set of
+ * attributes that can be used for View.getAttributes
+ *
+ * @param v - the view to get the set for
+ * @return the AttributeSet to use in the view.
+ */
+ public AttributeSet getViewAttributes(View v)
+ {
+ return new ViewAttributeSet(v, this);
+ }
+
+ /**
+ * Removes a style previously added.
+ *
+ * @param nm - the name of the style to remove
+ */
+ public void removeStyle(String nm)
+ {
+ // FIXME: Not implemented.
+ super.removeStyle(nm);
+ }
+
+ /**
+ * Adds the rules from ss to those of the receiver. ss's rules will
+ * override the old rules. An added StyleSheet will never override the rules
+ * of the receiving style sheet.
+ *
+ * @param ss - the new StyleSheet.
+ */
+ public void addStyleSheet(StyleSheet ss)
+ {
+ if (linked == null)
+ linked = new ArrayList<StyleSheet>();
+ linked.add(ss);
+ }
+
+ /**
+ * Removes ss from those of the receiver
+ *
+ * @param ss - the StyleSheet to remove.
+ */
+ public void removeStyleSheet(StyleSheet ss)
+ {
+ if (linked != null)
+ {
+ linked.remove(ss);
+ }
+ }
+
+ /**
+ * Returns an array of the linked StyleSheets. May return null.
+ *
+ * @return - An array of the linked StyleSheets.
+ */
+ public StyleSheet[] getStyleSheets()
+ {
+ StyleSheet[] linkedSS;
+ if (linked != null)
+ {
+ linkedSS = new StyleSheet[linked.size()];
+ linkedSS = linked.toArray(linkedSS);
+ }
+ else
+ {
+ linkedSS = null;
+ }
+ return linkedSS;
+ }
+
+ /**
+ * Imports a style sheet from the url. The rules are directly added to the
+ * receiver. This is usually called when a <link> tag is resolved in an
+ * HTML document.
+ *
+ * @param url the URL to import the StyleSheet from
+ */
+ public void importStyleSheet(URL url)
+ {
+ 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;
+ }
+
+ /**
+ * Gets the base url.
+ *
+ * @return - the base
+ */
+ public URL getBase()
+ {
+ 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,
+ String value)
+ {
+ // FIXME: Need to parse value from HTML based on key.
+ attr.addAttribute(key, value);
+ return attr.containsAttribute(key, value);
+ }
+
+ /**
+ * Converts a set of HTML attributes to an equivalent set of CSS attributes.
+ *
+ * @param htmlAttrSet - the set containing the HTML attributes.
+ * @return the set of CSS attributes
+ */
+ public AttributeSet translateHTMLToCSS(AttributeSet htmlAttrSet)
+ {
+ AttributeSet cssAttr = htmlAttrSet.copyAttributes();
+
+ // The HTML align attribute maps directly to the CSS text-align attribute.
+ Object o = htmlAttrSet.getAttribute(HTML.Attribute.ALIGN);
+ if (o != null)
+ cssAttr = addAttribute(cssAttr, CSS.Attribute.TEXT_ALIGN, o);
+
+ // The HTML width attribute maps directly to CSS width.
+ o = htmlAttrSet.getAttribute(HTML.Attribute.WIDTH);
+ if (o != null)
+ cssAttr = addAttribute(cssAttr, CSS.Attribute.WIDTH,
+ new Length(o.toString()));
+
+ // The HTML height attribute maps directly to CSS height.
+ o = htmlAttrSet.getAttribute(HTML.Attribute.HEIGHT);
+ if (o != null)
+ cssAttr = addAttribute(cssAttr, CSS.Attribute.HEIGHT,
+ new Length(o.toString()));
+
+ o = htmlAttrSet.getAttribute(HTML.Attribute.NOWRAP);
+ if (o != null)
+ cssAttr = addAttribute(cssAttr, CSS.Attribute.WHITE_SPACE, "nowrap");
+
+ // Map cellspacing attr of tables to CSS border-spacing.
+ o = htmlAttrSet.getAttribute(HTML.Attribute.CELLSPACING);
+ if (o != null)
+ cssAttr = addAttribute(cssAttr, CSS.Attribute.BORDER_SPACING,
+ new Length(o.toString()));
+
+ // For table cells and headers, fetch the cellpadding value from the
+ // parent table and set it as CSS padding attribute.
+ HTML.Tag tag = (HTML.Tag)
+ htmlAttrSet.getAttribute(StyleConstants.NameAttribute);
+ if ((tag == HTML.Tag.TD || tag == HTML.Tag.TH)
+ && htmlAttrSet instanceof Element)
+ {
+ Element el = (Element) htmlAttrSet;
+ AttributeSet tableAttrs = el.getParentElement().getParentElement()
+ .getAttributes();
+ o = tableAttrs.getAttribute(HTML.Attribute.CELLPADDING);
+ if (o != null)
+ {
+ Length l = new Length(o.toString());
+ cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING_BOTTOM, l);
+ cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING_LEFT, l);
+ cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING_RIGHT, l);
+ cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING_TOP, l);
+ }
+ o = tableAttrs.getAttribute(HTML.Attribute.BORDER);
+ cssAttr = translateBorder(cssAttr, o);
+ }
+
+ // Translate border attribute.
+ o = cssAttr.getAttribute(HTML.Attribute.BORDER);
+ cssAttr = translateBorder(cssAttr, o);
+
+ // TODO: Add more mappings.
+ return cssAttr;
+ }
+
+ /**
+ * Translates a HTML border attribute to a corresponding set of CSS
+ * attributes.
+ *
+ * @param cssAttr the original set of CSS attributes to add to
+ * @param o the value of the border attribute
+ *
+ * @return the new set of CSS attributes
+ */
+ private AttributeSet translateBorder(AttributeSet cssAttr, Object o)
+ {
+ if (o != null)
+ {
+ BorderWidth l = new BorderWidth(o.toString());
+ if (l.getValue() > 0)
+ {
+ cssAttr = addAttribute(cssAttr, CSS.Attribute.BORDER_WIDTH, l);
+ cssAttr = addAttribute(cssAttr, CSS.Attribute.BORDER_STYLE,
+ "solid");
+ cssAttr = addAttribute(cssAttr, CSS.Attribute.BORDER_COLOR,
+ new CSSColor("black"));
+ }
+ }
+ return cssAttr;
+ }
+
+ /**
+ * Adds an attribute to the given set and returns a new set. This is implemented
+ * to convert StyleConstants attributes to CSS before forwarding them to the superclass.
+ * The StyleConstants attribute do not have corresponding CSS entry, the attribute
+ * is stored (but will likely not be used).
+ *
+ * @param old - the old set
+ * @param key - the non-null attribute key
+ * @param value - the attribute value
+ * @return the updated set
+ */
+ public AttributeSet addAttribute(AttributeSet old, Object key,
+ Object value)
+ {
+ // FIXME: Not implemented.
+ return super.addAttribute(old, key, value);
+ }
+
+ /**
+ * Adds a set of attributes to the element. If any of these attributes are
+ * StyleConstants, they will be converted to CSS before forwarding to the
+ * superclass.
+ *
+ * @param old - the old set
+ * @param attr - the attributes to add
+ * @return the updated attribute set
+ */
+ public AttributeSet addAttributes(AttributeSet old, AttributeSet attr)
+ {
+ // FIXME: Not implemented.
+ return super.addAttributes(old, attr);
+ }
+
+ /**
+ * Removes an attribute from the set. If the attribute is a
+ * StyleConstants, it will be converted to CSS before forwarding to the
+ * superclass.
+ *
+ * @param old - the old set
+ * @param key - the non-null attribute key
+ * @return the updated set
+ */
+ public AttributeSet removeAttribute(AttributeSet old, Object key)
+ {
+ // FIXME: Not implemented.
+ return super.removeAttribute(old, key);
+ }
+
+ /**
+ * Removes an attribute from the set. If any of the attributes are
+ * StyleConstants, they will be converted to CSS before forwarding to the
+ * superclass.
+ *
+ * @param old - the old set
+ * @param attrs - the attributes to remove
+ * @return the updated set
+ */
+ public AttributeSet removeAttributes(AttributeSet old, AttributeSet attrs)
+ {
+ // FIXME: Not implemented.
+ return super.removeAttributes(old, attrs);
+ }
+
+ /**
+ * Removes a set of attributes for the element. If any of the attributes is a
+ * StyleConstants, they will be converted to CSS before forwarding to the
+ * superclass.
+ *
+ * @param old - the old attribute set
+ * @param names - the attribute names
+ * @return the update attribute set
+ */
+ public AttributeSet removeAttributes(AttributeSet old, Enumeration<?> names)
+ {
+ // FIXME: Not implemented.
+ return super.removeAttributes(old, names);
+ }
+
+ /**
+ * Creates a compact set of attributes that might be shared. This is a hook
+ * for subclasses that want to change the behaviour of SmallAttributeSet.
+ *
+ * @param a - the set of attributes to be represented in the compact form.
+ * @return the set of attributes created
+ */
+ protected StyleContext.SmallAttributeSet createSmallAttributeSet(AttributeSet a)
+ {
+ return super.createSmallAttributeSet(a);
+ }
+
+ /**
+ * Creates a large set of attributes. This set is not shared. This is a hook
+ * for subclasses that want to change the behaviour of the larger attribute
+ * storage format.
+ *
+ * @param a - the set of attributes to be represented in the larger form.
+ * @return the large set of attributes.
+ */
+ protected MutableAttributeSet createLargeAttributeSet(AttributeSet a)
+ {
+ return super.createLargeAttributeSet(a);
+ }
+
+ /**
+ * Gets the font to use for the given set.
+ *
+ * @param a - the set to get the font for.
+ * @return the font for the set
+ */
+ public Font getFont(AttributeSet a)
+ {
+ int realSize = getFontSize(a);
+
+ // Decrement size for subscript and superscript.
+ Object valign = a.getAttribute(CSS.Attribute.VERTICAL_ALIGN);
+ if (valign != null)
+ {
+ String v = valign.toString();
+ if (v.contains("sup") || v.contains("sub"))
+ realSize -= 2;
+ }
+
+ // TODO: Convert font family.
+ String family = "SansSerif";
+
+ int style = Font.PLAIN;
+ FontWeight weight = (FontWeight) a.getAttribute(CSS.Attribute.FONT_WEIGHT);
+ if (weight != null)
+ style |= weight.getValue();
+ FontStyle fStyle = (FontStyle) a.getAttribute(CSS.Attribute.FONT_STYLE);
+ if (fStyle != null)
+ style |= fStyle.getValue();
+ return new Font(family, style, realSize);
+ }
+
+ /**
+ * Determines the EM base value based on the specified attributes.
+ *
+ * @param atts the attibutes
+ *
+ * @return the EM base value
+ */
+ float getEMBase(AttributeSet atts)
+ {
+ Font font = getFont(atts);
+ FontRenderContext ctx = new FontRenderContext(null, false, false);
+ Rectangle2D bounds = font.getStringBounds("M", ctx);
+ return (float) bounds.getWidth();
+ }
+
+ /**
+ * Determines the EX base value based on the specified attributes.
+ *
+ * @param atts the attibutes
+ *
+ * @return the EX base value
+ */
+ float getEXBase(AttributeSet atts)
+ {
+ Font font = getFont(atts);
+ FontRenderContext ctx = new FontRenderContext(null, false, false);
+ Rectangle2D bounds = font.getStringBounds("x", ctx);
+ return (float) bounds.getHeight();
+ }
+
+ /**
+ * Resolves the fontsize for a given set of attributes.
+ *
+ * @param atts the attributes
+ *
+ * @return the resolved font size
+ */
+ private int getFontSize(AttributeSet atts)
+ {
+ int size = 12;
+ if (atts.isDefined(CSS.Attribute.FONT_SIZE))
+ {
+ FontSize fs = (FontSize) atts.getAttribute(CSS.Attribute.FONT_SIZE);
+ if (fs.isRelative())
+ {
+ int parSize = 12;
+ AttributeSet resolver = atts.getResolveParent();
+ if (resolver != null)
+ parSize = getFontSize(resolver);
+ size = fs.getValue(parSize);
+ }
+ else
+ {
+ size = fs.getValue();
+ }
+ }
+ else
+ {
+ AttributeSet resolver = atts.getResolveParent();
+ if (resolver != null)
+ size = getFontSize(resolver);
+ }
+ return size;
+ }
+
+ /**
+ * Takes a set of attributes and turns it into a foreground
+ * color specification. This is used to specify things like, brigher, more hue
+ * etc.
+ *
+ * @param a - the set to get the foreground color for
+ * @return the foreground color for the set
+ */
+ public Color getForeground(AttributeSet a)
+ {
+ CSSColor c = (CSSColor) a.getAttribute(CSS.Attribute.COLOR);
+ Color color = null;
+ if (c != null)
+ color = c.getValue();
+ return color;
+ }
+
+ /**
+ * Takes a set of attributes and turns it into a background
+ * color specification. This is used to specify things like, brigher, more hue
+ * etc.
+ *
+ * @param a - the set to get the background color for
+ * @return the background color for the set
+ */
+ public Color getBackground(AttributeSet a)
+ {
+ CSSColor c = (CSSColor) a.getAttribute(CSS.Attribute.BACKGROUND_COLOR);
+ Color color = null;
+ if (c != null)
+ color = c.getValue();
+ return color;
+ }
+
+ /**
+ * Gets the box formatter to use for the given set of CSS attributes.
+ *
+ * @param a - the given set
+ * @return the box formatter
+ */
+ public BoxPainter getBoxPainter(AttributeSet a)
+ {
+ return new BoxPainter(a, this);
+ }
+
+ /**
+ * Gets the list formatter to use for the given set of CSS attributes.
+ *
+ * @param a - the given set
+ * @return the list formatter
+ */
+ public ListPainter getListPainter(AttributeSet a)
+ {
+ return new ListPainter(a, this);
+ }
+
+ /**
+ * Sets the base font size between 1 and 7.
+ *
+ * @param sz - the new font size for the base.
+ */
+ public void setBaseFontSize(int sz)
+ {
+ if (sz <= 7 && sz >= 1)
+ baseFontSize = sz;
+ }
+
+ /**
+ * Sets the base font size from the String. It can either identify
+ * a specific font size (between 1 and 7) or identify a relative
+ * font size such as +1 or -2.
+ *
+ * @param size - the new font size as a String.
+ */
+ public void setBaseFontSize(String size)
+ {
+ size = size.trim();
+ int temp = 0;
+ try
+ {
+ if (size.length() == 2)
+ {
+ int i = new Integer(size.substring(1)).intValue();
+ if (size.startsWith("+"))
+ temp = baseFontSize + i;
+ else if (size.startsWith("-"))
+ temp = baseFontSize - i;
+ }
+ else if (size.length() == 1)
+ temp = new Integer(size.substring(0)).intValue();
+
+ if (temp <= 7 && temp >= 1)
+ baseFontSize = temp;
+ }
+ catch (NumberFormatException nfe)
+ {
+ // Do nothing here
+ }
+ }
+
+ /**
+ * TODO
+ *
+ * @param pt - TODO
+ * @return TODO
+ */
+ public static int getIndexOfSize(float pt)
+ {
+ // FIXME: Not implemented.
+ return 0;
+ }
+
+ /**
+ * Gets the point size, given a size index.
+ *
+ * @param index - the size index
+ * @return the point size.
+ */
+ public float getPointSize(int index)
+ {
+ // FIXME: Not implemented.
+ return 0;
+ }
+
+ /**
+ * Given the string of the size, returns the point size value.
+ *
+ * @param size - the string representation of the size.
+ * @return - the point size value.
+ */
+ public float getPointSize(String size)
+ {
+ // FIXME: Not implemented.
+ return 0;
+ }
+
+ /**
+ * Convert the color string represenation into java.awt.Color. The valid
+ * values are like "aqua" , "#00FFFF" or "rgb(1,6,44)".
+ *
+ * @param colorName the color to convert.
+ * @return the matching java.awt.color
+ */
+ public Color stringToColor(String colorName)
+ {
+ return CSSColor.convertValue(colorName);
+ }
+
+ /**
+ * This class carries out some of the duties of CSS formatting. This enables views
+ * to present the CSS formatting while not knowing how the CSS values are cached.
+ *
+ * This object is reponsible for the insets of a View and making sure
+ * the background is maintained according to the CSS attributes.
+ *
+ * @author Lillian Angel (langel@redhat.com)
+ */
+ public static class BoxPainter extends Object implements Serializable
+ {
+
+ /**
+ * The left inset.
+ */
+ private float leftInset;
+
+ /**
+ * The right inset.
+ */
+ private float rightInset;
+
+ /**
+ * The top inset.
+ */
+ private float topInset;
+
+ /**
+ * The bottom inset.
+ */
+ private float bottomInset;
+
+ /**
+ * The border of the box.
+ */
+ private Border border;
+
+ private float leftPadding;
+ private float rightPadding;
+ private float topPadding;
+ private float bottomPadding;
+
+ /**
+ * The background color.
+ */
+ private Color background;
+
+ /**
+ * Package-private constructor.
+ *
+ * @param as - AttributeSet for painter
+ */
+ BoxPainter(AttributeSet as, StyleSheet ss)
+ {
+ float emBase = ss.getEMBase(as);
+ float exBase = ss.getEXBase(as);
+ // Fetch margins.
+ Length l = (Length) as.getAttribute(CSS.Attribute.MARGIN_LEFT);
+ if (l != null)
+ {
+ l.setFontBases(emBase, exBase);
+ leftInset = l.getValue();
+ }
+ l = (Length) as.getAttribute(CSS.Attribute.MARGIN_RIGHT);
+ if (l != null)
+ {
+ l.setFontBases(emBase, exBase);
+ rightInset = l.getValue();
+ }
+ l = (Length) as.getAttribute(CSS.Attribute.MARGIN_TOP);
+ if (l != null)
+ {
+ l.setFontBases(emBase, exBase);
+ topInset = l.getValue();
+ }
+ l = (Length) as.getAttribute(CSS.Attribute.MARGIN_BOTTOM);
+ if (l != null)
+ {
+ l.setFontBases(emBase, exBase);
+ bottomInset = l.getValue();
+ }
+
+ // Fetch padding.
+ l = (Length) as.getAttribute(CSS.Attribute.PADDING_LEFT);
+ if (l != null)
+ {
+ l.setFontBases(emBase, exBase);
+ leftPadding = l.getValue();
+ }
+ l = (Length) as.getAttribute(CSS.Attribute.PADDING_RIGHT);
+ if (l != null)
+ {
+ l.setFontBases(emBase, exBase);
+ rightPadding = l.getValue();
+ }
+ l = (Length) as.getAttribute(CSS.Attribute.PADDING_TOP);
+ if (l != null)
+ {
+ l.setFontBases(emBase, exBase);
+ topPadding = l.getValue();
+ }
+ l = (Length) as.getAttribute(CSS.Attribute.PADDING_BOTTOM);
+ if (l != null)
+ {
+ l.setFontBases(emBase, exBase);
+ bottomPadding = l.getValue();
+ }
+
+ // Determine border.
+ border = new CSSBorder(as, ss);
+
+ // Determine background.
+ background = ss.getBackground(as);
+
+ }
+
+
+ /**
+ * Gets the inset needed on a given side to account for the margin, border
+ * and padding.
+ *
+ * @param size - the size of the box to get the inset for. View.TOP, View.LEFT,
+ * View.BOTTOM or View.RIGHT.
+ * @param v - the view making the request. This is used to get the AttributeSet,
+ * amd may be used to resolve percentage arguments.
+ * @return the inset
+ * @throws IllegalArgumentException - for an invalid direction.
+ */
+ public float getInset(int size, View v)
+ {
+ float inset;
+ switch (size)
+ {
+ case View.TOP:
+ inset = topInset;
+ if (border != null)
+ inset += border.getBorderInsets(null).top;
+ inset += topPadding;
+ break;
+ case View.BOTTOM:
+ inset = bottomInset;
+ if (border != null)
+ inset += border.getBorderInsets(null).bottom;
+ inset += bottomPadding;
+ break;
+ case View.LEFT:
+ inset = leftInset;
+ if (border != null)
+ inset += border.getBorderInsets(null).left;
+ inset += leftPadding;
+ break;
+ case View.RIGHT:
+ inset = rightInset;
+ if (border != null)
+ inset += border.getBorderInsets(null).right;
+ inset += rightPadding;
+ break;
+ default:
+ inset = 0.0F;
+ }
+ return inset;
+ }
+
+ /**
+ * Paints the CSS box according to the attributes given. This should
+ * paint the border, padding and background.
+ *
+ * @param g - the graphics configuration
+ * @param x - the x coordinate
+ * @param y - the y coordinate
+ * @param w - the width of the allocated area
+ * @param h - the height of the allocated area
+ * @param v - the view making the request
+ */
+ public void paint(Graphics g, float x, float y, float w, float h, View v)
+ {
+ int inX = (int) (x + leftInset);
+ int inY = (int) (y + topInset);
+ int inW = (int) (w - leftInset - rightInset);
+ int inH = (int) (h - topInset - bottomInset);
+ if (background != null)
+ {
+ g.setColor(background);
+ g.fillRect(inX, inY, inW, inH);
+ }
+ if (border != null)
+ {
+ border.paintBorder(null, g, inX, inY, inW, inH);
+ }
+ }
+ }
+
+ /**
+ * This class carries out some of the CSS list formatting duties. Implementations
+ * of this class enable views to present the CSS formatting while not knowing anything
+ * about how the CSS values are being cached.
+ *
+ * @author Lillian Angel (langel@redhat.com)
+ */
+ public static class ListPainter implements Serializable
+ {
+
+ /**
+ * Attribute set for painter
+ */
+ private AttributeSet attributes;
+
+ /**
+ * The associated style sheet.
+ */
+ private StyleSheet styleSheet;
+
+ /**
+ * The bullet type.
+ */
+ private String type;
+
+ /**
+ * Package-private constructor.
+ *
+ * @param as - AttributeSet for painter
+ */
+ ListPainter(AttributeSet as, StyleSheet ss)
+ {
+ attributes = as;
+ styleSheet = ss;
+ type = (String) as.getAttribute(CSS.Attribute.LIST_STYLE_TYPE);
+ }
+
+ /**
+ * Cached rectangle re-used in the paint method below.
+ */
+ private final Rectangle tmpRect = new Rectangle();
+
+ /**
+ * Paints the CSS list decoration according to the attributes given.
+ *
+ * @param g - the graphics configuration
+ * @param x - the x coordinate
+ * @param y - the y coordinate
+ * @param w - the width of the allocated area
+ * @param h - the height of the allocated area
+ * @param v - the view making the request
+ * @param item - the list item to be painted >=0.
+ */
+ public void paint(Graphics g, float x, float y, float w, float h, View v,
+ int item)
+ {
+ // FIXME: This is a very simplistic list rendering. We still need
+ // to implement different bullet types (see type field) and custom
+ // bullets via images.
+ View itemView = v.getView(item);
+ AttributeSet viewAtts = itemView.getAttributes();
+ Object tag = viewAtts.getAttribute(StyleConstants.NameAttribute);
+ // Only paint something here when the child view is an LI tag
+ // and the calling view is some of the list tags then).
+ if (tag != null && tag == HTML.Tag.LI)
+ {
+ g.setColor(Color.BLACK);
+ int centerX = (int) (x - 12);
+ int centerY = -1;
+ // For paragraphs (almost all cases) center bullet vertically
+ // in the middle of the first line.
+ tmpRect.setBounds((int) x, (int) y, (int) w, (int) h);
+ if (itemView.getViewCount() > 0)
+ {
+ View v1 = itemView.getView(0);
+ if (v1 instanceof ParagraphView && v1.getViewCount() > 0)
+ {
+ Shape a1 = itemView.getChildAllocation(0, tmpRect);
+ Rectangle r1 = a1 instanceof Rectangle ? (Rectangle) a1
+ : a1.getBounds();
+ ParagraphView par = (ParagraphView) v1;
+ Shape a = par.getChildAllocation(0, r1);
+ if (a != null)
+ {
+ Rectangle r = a instanceof Rectangle ? (Rectangle) a
+ : a.getBounds();
+ centerY = (int) (r.height / 2 + r.y);
+ }
+ }
+ }
+ if (centerY == -1)
+ {
+ centerY =(int) (h / 2 + y);
+ }
+ g.fillOval(centerX - 3, centerY - 3, 6, 6);
+ }
+ }
+ }
+
+ /**
+ * Converts an AttributeSet to a Map. This is used for CSS resolving.
+ *
+ * @param atts the attributes to convert
+ *
+ * @return the converted map
+ */
+ private Map<String,String> attributeSetToMap(AttributeSet atts)
+ {
+ HashMap<String,String> map = new HashMap<String,String>();
+ Enumeration<?> keys = atts.getAttributeNames();
+ while (keys.hasMoreElements())
+ {
+ Object key = keys.nextElement();
+ Object value = atts.getAttribute(key);
+ map.put(key.toString(), value.toString());
+ }
+ return map;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/TableView.java b/libjava/classpath/javax/swing/text/html/TableView.java
new file mode 100644
index 000000000..2ad1b6d38
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/TableView.java
@@ -0,0 +1,974 @@
+/* TableView.java -- A table view for HTML tables
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+import gnu.javax.swing.text.html.css.Length;
+
+import javax.swing.SizeRequirements;
+import javax.swing.event.DocumentEvent;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.Element;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+
+/**
+ * A view implementation that renders HTML tables.
+ *
+ * This is basically a vertical BoxView that contains the rows of the table
+ * and the rows are horizontal BoxViews that contain the actual columns.
+ */
+class TableView
+ extends BlockView
+ implements ViewFactory
+{
+
+ /**
+ * Represents a single table row.
+ */
+ class RowView
+ extends BlockView
+ {
+ /**
+ * Has true at column positions where an above row's cell overlaps into
+ * this row.
+ */
+ boolean[] overlap;
+
+ /**
+ * Stores the row index of this row.
+ */
+ int rowIndex;
+
+ /**
+ * Creates a new RowView.
+ *
+ * @param el the element for the row view
+ */
+ RowView(Element el)
+ {
+ super(el, X_AXIS);
+ }
+
+ public void replace(int offset, int len, View[] views)
+ {
+ gridValid = false;
+ super.replace(offset, len, views);
+ }
+
+ /**
+ * Overridden to make rows not resizable along the Y axis.
+ */
+ public float getMaximumSpan(int axis)
+ {
+ float span;
+ if (axis == Y_AXIS)
+ span = super.getPreferredSpan(axis);
+ else
+ span = Integer.MAX_VALUE;
+ return span;
+ }
+
+ public float getMinimumSpan(int axis)
+ {
+ float span;
+ if (axis == X_AXIS)
+ span = totalColumnRequirements.minimum;
+ else
+ span = super.getMinimumSpan(axis);
+ return span;
+ }
+
+ public float getPreferredSpan(int axis)
+ {
+ float span;
+ if (axis == X_AXIS)
+ span = totalColumnRequirements.preferred;
+ else
+ span = super.getPreferredSpan(axis);
+ return span;
+ }
+
+ /**
+ * Calculates the overall size requirements for the row along the
+ * major axis. This will be the sum of the column requirements.
+ */
+ protected SizeRequirements calculateMajorAxisRequirements(int axis,
+ SizeRequirements r)
+ {
+ if (r == null)
+ r = new SizeRequirements();
+ int adjust = (columnRequirements.length + 1) * cellSpacing;
+ r.minimum = totalColumnRequirements.minimum + adjust;
+ r.preferred = totalColumnRequirements.preferred + adjust;
+ r.maximum = totalColumnRequirements.maximum + adjust;
+ r.alignment = 0.0F;
+ return r;
+ }
+
+ /**
+ * Lays out the columns in this row.
+ */
+ protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
+ int spans[])
+ {
+ super.layoutMinorAxis(targetSpan, axis, offsets, spans);
+
+ // Adjust columns that have rowSpan > 1.
+ int numCols = getViewCount();
+ for (int i = 0; i < numCols; i++)
+ {
+ View v = getView(i);
+ if (v instanceof CellView)
+ {
+ CellView cell = (CellView) v;
+ if (cell.rowSpan > 1)
+ {
+ for (int r = 1; r < cell.rowSpan; r++)
+ {
+ spans[i] += TableView.this.getSpan(axis, rowIndex + r);
+ spans[i] += cellSpacing;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Lays out the columns in this row.
+ */
+ protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
+ int spans[])
+ {
+ updateGrid();
+ int realColumn = 0;
+ int colCount = getViewCount();
+ for (int i = 0; i < numColumns;)
+ {
+ if (! overlap[i] && realColumn < colCount)
+ {
+ View v = getView(realColumn);
+ if (v instanceof CellView)
+ {
+ CellView cv = (CellView) v;
+ offsets[realColumn] = columnOffsets[i];
+ spans[realColumn] = 0;
+ for (int j = 0; j < cv.colSpan; j++, i++)
+ {
+ spans[realColumn] += columnSpans[i];
+ if (j < cv.colSpan - 1)
+ spans[realColumn] += cellSpacing;
+ }
+ }
+ realColumn++;
+ }
+ else
+ {
+ i++;
+ }
+ }
+ }
+ }
+
+ /**
+ * A view that renders HTML table cells (TD and TH tags).
+ */
+ class CellView
+ extends BlockView
+ {
+
+ /**
+ * The number of columns that this view spans.
+ */
+ int colSpan;
+
+ /**
+ * The number of rows that this cell spans.
+ */
+ int rowSpan;
+
+ /**
+ * Creates a new CellView for the specified element.
+ *
+ * @param el the element for which to create the colspan
+ */
+ CellView(Element el)
+ {
+ super(el, Y_AXIS);
+ }
+
+ protected SizeRequirements calculateMajorAxisRequirements(int axis,
+ SizeRequirements r)
+ {
+ r = super.calculateMajorAxisRequirements(axis, r);
+ r.maximum = Integer.MAX_VALUE;
+ return r;
+ }
+
+ /**
+ * Overridden to fetch the columnSpan attibute.
+ */
+ protected void setPropertiesFromAttributes()
+ {
+ super.setPropertiesFromAttributes();
+ colSpan = 1;
+ AttributeSet atts = getAttributes();
+ Object o = atts.getAttribute(HTML.Attribute.COLSPAN);
+ if (o != null)
+ {
+ try
+ {
+ colSpan = Integer.parseInt(o.toString());
+ }
+ catch (NumberFormatException ex)
+ {
+ // Couldn't parse the colspan, assume 1.
+ colSpan = 1;
+ }
+ }
+ rowSpan = 1;
+ o = atts.getAttribute(HTML.Attribute.ROWSPAN);
+ if (o != null)
+ {
+ try
+ {
+ rowSpan = Integer.parseInt(o.toString());
+ }
+ catch (NumberFormatException ex)
+ {
+ // Couldn't parse the colspan, assume 1.
+ rowSpan = 1;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * The attributes of this view.
+ */
+ private AttributeSet attributes;
+
+ /**
+ * The column requirements.
+ *
+ * Package private to avoid accessor methods.
+ */
+ SizeRequirements[] columnRequirements;
+
+ /**
+ * The overall requirements across all columns.
+ *
+ * Package private to avoid accessor methods.
+ */
+ SizeRequirements totalColumnRequirements;
+
+ /**
+ * The column layout, offsets.
+ *
+ * Package private to avoid accessor methods.
+ */
+ int[] columnOffsets;
+
+ /**
+ * The column layout, spans.
+ *
+ * Package private to avoid accessor methods.
+ */
+ int[] columnSpans;
+
+ /**
+ * The widths of the columns that have been explicitly specified.
+ */
+ Length[] columnWidths;
+
+ /**
+ * The total number of columns.
+ */
+ int numColumns;
+
+ /**
+ * The table width.
+ */
+ private Length width;
+
+ /**
+ * Indicates if the grid setup is ok.
+ */
+ boolean gridValid = false;
+
+ /**
+ * Additional space that is added _between_ table cells.
+ *
+ * This is package private to avoid accessor methods.
+ */
+ int cellSpacing;
+
+ /**
+ * A cached Rectangle object for reuse in paint().
+ */
+ private Rectangle tmpRect;
+
+ /**
+ * Creates a new HTML table view for the specified element.
+ *
+ * @param el the element for the table view
+ */
+ public TableView(Element el)
+ {
+ super(el, Y_AXIS);
+ totalColumnRequirements = new SizeRequirements();
+ tmpRect = new Rectangle();
+ }
+
+ /**
+ * Implementation of the ViewFactory interface for creating the
+ * child views correctly.
+ */
+ public View create(Element elem)
+ {
+ View view = null;
+ AttributeSet atts = elem.getAttributes();
+ Object name = atts.getAttribute(StyleConstants.NameAttribute);
+ AttributeSet pAtts = elem.getParentElement().getAttributes();
+ Object pName = pAtts.getAttribute(StyleConstants.NameAttribute);
+
+ if (name == HTML.Tag.TR && pName == HTML.Tag.TABLE)
+ view = new RowView(elem);
+ else if ((name == HTML.Tag.TD || name == HTML.Tag.TH)
+ && pName == HTML.Tag.TR)
+ view = new CellView(elem);
+ else if (name == HTML.Tag.CAPTION)
+ view = new ParagraphView(elem);
+ else
+ {
+ // If we haven't mapped the element, then fall back to the standard
+ // view factory.
+ View parent = getParent();
+ if (parent != null)
+ {
+ ViewFactory vf = parent.getViewFactory();
+ if (vf != null)
+ view = vf.create(elem);
+ }
+ }
+ return view;
+ }
+
+ /**
+ * Returns this object as view factory so that we get our TR, TD, TH
+ * and CAPTION subelements created correctly.
+ */
+ public ViewFactory getViewFactory()
+ {
+ return this;
+ }
+
+ /**
+ * Returns the attributes of this view. This is overridden to provide
+ * the attributes merged with the CSS stuff.
+ */
+ public AttributeSet getAttributes()
+ {
+ if (attributes == null)
+ attributes = getStyleSheet().getViewAttributes(this);
+ return attributes;
+ }
+
+ /**
+ * Returns the stylesheet associated with this view.
+ *
+ * @return the stylesheet associated with this view
+ */
+ protected StyleSheet getStyleSheet()
+ {
+ HTMLDocument doc = (HTMLDocument) getDocument();
+ return doc.getStyleSheet();
+ }
+
+ /**
+ * Overridden to calculate the size requirements according to the
+ * columns distribution.
+ */
+ protected SizeRequirements calculateMinorAxisRequirements(int axis,
+ SizeRequirements r)
+ {
+ updateGrid();
+ calculateColumnRequirements();
+
+ // Calculate the horizontal requirements according to the superclass.
+ // This will return the maximum of the row's widths.
+ r = super.calculateMinorAxisRequirements(axis, r);
+
+ // Try to set the CSS width if it fits.
+ if (width != null)
+ {
+ int w = (int) width.getValue();
+ if (r.minimum < w)
+ r.minimum = w;
+ }
+
+ // Adjust requirements when we have cell spacing.
+ int adjust = (columnRequirements.length + 1) * cellSpacing;
+ r.minimum += adjust;
+ r.preferred += adjust;
+
+ // Apply the alignment.
+ AttributeSet atts = getAttributes();
+ Object o = atts.getAttribute(CSS.Attribute.TEXT_ALIGN);
+ r.alignment = 0.0F;
+ if (o != null)
+ {
+ String al = o.toString();
+ if (al.equals("left"))
+ r.alignment = 0.0F;
+ else if (al.equals("center"))
+ r.alignment = 0.5F;
+ else if (al.equals("right"))
+ r.alignment = 1.0F;
+ }
+
+ // Make it not resize in the horizontal direction.
+ r.maximum = r.preferred;
+ return r;
+ }
+
+ /**
+ * Overridden to perform the table layout before calling the super
+ * implementation.
+ */
+ protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
+ int[] spans)
+ {
+ updateGrid();
+
+ // Mark all rows as invalid along their minor axis to force correct
+ // layout of multi-row cells.
+ int n = getViewCount();
+ for (int i = 0; i < n; i++)
+ {
+ View row = getView(i);
+ if (row instanceof RowView)
+ ((RowView) row).layoutChanged(axis);
+ }
+
+ layoutColumns(targetSpan);
+ super.layoutMinorAxis(targetSpan, axis, offsets, spans);
+ }
+
+ /**
+ * Calculates the size requirements for the columns.
+ */
+ private void calculateColumnRequirements()
+ {
+ int numRows = getViewCount();
+ totalColumnRequirements.minimum = 0;
+ totalColumnRequirements.preferred = 0;
+ totalColumnRequirements.maximum = 0;
+
+ // In this first pass we find out a suitable total width to fit in
+ // all columns of all rows.
+ for (int r = 0; r < numRows; r++)
+ {
+ View rowView = getView(r);
+ int numCols;
+ if (rowView instanceof RowView)
+ numCols = ((RowView) rowView).getViewCount();
+ else
+ numCols = 0;
+
+ // We collect the normal (non-relative) column requirements in the
+ // total variable and the relative requirements in the relTotal
+ // variable. In the end we create the maximum of both to get the
+ // real requirements.
+ SizeRequirements total = new SizeRequirements();
+ SizeRequirements relTotal = new SizeRequirements();
+ float totalPercent = 0.F;
+ int realCol = 0;
+ for (int c = 0; c < numCols; c++)
+ {
+ View v = rowView.getView(c);
+ if (v instanceof CellView)
+ {
+ CellView cellView = (CellView) v;
+ int colSpan = cellView.colSpan;
+ if (colSpan > 1)
+ {
+ int cellMin = (int) cellView.getMinimumSpan(X_AXIS);
+ int cellPref = (int) cellView.getPreferredSpan(X_AXIS);
+ int cellMax = (int) cellView.getMaximumSpan(X_AXIS);
+ int currentMin = 0;
+ int currentPref = 0;
+ long currentMax = 0;
+ for (int i = 0; i < colSpan; i++)
+ {
+ SizeRequirements req = columnRequirements[realCol];
+ currentMin += req.minimum;
+ currentPref += req.preferred;
+ currentMax += req.maximum;
+ }
+ int deltaMin = cellMin - currentMin;
+ int deltaPref = cellPref - currentPref;
+ int deltaMax = (int) (cellMax - currentMax);
+ // Distribute delta.
+ for (int i = 0; i < colSpan; i++)
+ {
+ SizeRequirements req = columnRequirements[realCol];
+ if (deltaMin > 0)
+ req.minimum += deltaMin / colSpan;
+ if (deltaPref > 0)
+ req.preferred += deltaPref / colSpan;
+ if (deltaMax > 0)
+ req.maximum += deltaMax / colSpan;
+ if (columnWidths[realCol] == null
+ || ! columnWidths[realCol].isPercentage())
+ {
+ total.minimum += req.minimum;
+ total.preferred += req.preferred;
+ total.maximum += req.maximum;
+ }
+ else
+ {
+ relTotal.minimum =
+ Math.max(relTotal.minimum,
+ (int) (req.minimum
+ * columnWidths[realCol].getValue()));
+ relTotal.preferred =
+ Math.max(relTotal.preferred,
+ (int) (req.preferred
+ * columnWidths[realCol].getValue()));
+ relTotal.maximum =
+ Math.max(relTotal.maximum,
+ (int) (req.maximum
+ * columnWidths[realCol].getValue()));
+ totalPercent += columnWidths[realCol].getValue();
+ }
+ }
+ realCol += colSpan;
+ }
+ else
+ {
+ // Shortcut for colSpan == 1.
+ SizeRequirements req = columnRequirements[realCol];
+ req.minimum = Math.max(req.minimum,
+ (int) cellView.getMinimumSpan(X_AXIS));
+ req.preferred = Math.max(req.preferred,
+ (int) cellView.getPreferredSpan(X_AXIS));
+ req.maximum = Math.max(req.maximum,
+ (int) cellView.getMaximumSpan(X_AXIS));
+ if (columnWidths[realCol] == null
+ || ! columnWidths[realCol].isPercentage())
+ {
+ total.minimum += columnRequirements[realCol].minimum;
+ total.preferred +=
+ columnRequirements[realCol].preferred;
+ total.maximum += columnRequirements[realCol].maximum;
+ }
+ else
+ {
+ relTotal.minimum =
+ Math.max(relTotal.minimum,
+ (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();
+ }
+ realCol += 1;
+ }
+ }
+ }
+
+ // 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);
+ int rowTotalPref = Math.max(total.preferred, relTotal.preferred);
+ int rowTotalMax = Math.max(total.maximum, relTotal.maximum);
+ totalColumnRequirements.minimum =
+ Math.max(totalColumnRequirements.minimum, rowTotalMin);
+ totalColumnRequirements.preferred =
+ Math.max(totalColumnRequirements.preferred, rowTotalPref);
+ totalColumnRequirements.maximum =
+ Math.max(totalColumnRequirements.maximum, rowTotalMax);
+ }
+
+ // Now we know what we want and can fix up the actual relative
+ // column requirements.
+ int numCols = columnRequirements.length;
+ for (int i = 0; i < numCols; i++)
+ {
+ if (columnWidths[i] != null)
+ {
+ columnRequirements[i].minimum = (int)
+ columnWidths[i].getValue(totalColumnRequirements.minimum);
+ columnRequirements[i].preferred = (int)
+ columnWidths[i].getValue(totalColumnRequirements.preferred);
+ columnRequirements[i].maximum = (int)
+ columnWidths[i].getValue(totalColumnRequirements.maximum);
+ }
+ }
+ }
+
+ /**
+ * Lays out the columns.
+ *
+ * @param targetSpan the target span into which the table is laid out
+ */
+ private void layoutColumns(int targetSpan)
+ {
+ // Set the spans to the preferred sizes. Determine the space
+ // that we have to adjust the sizes afterwards.
+ long sumPref = 0;
+ int n = columnRequirements.length;
+ for (int i = 0; i < n; i++)
+ {
+ SizeRequirements col = columnRequirements[i];
+ if (columnWidths[i] != null)
+ columnSpans[i] = (int) columnWidths[i].getValue(targetSpan);
+ else
+ columnSpans[i] = col.preferred;
+ sumPref += columnSpans[i];
+ }
+
+ // Try to adjust the spans so that we fill the targetSpan.
+ // For adjustments we have to use the targetSpan minus the cumulated
+ // cell spacings.
+ long diff = targetSpan - (n + 1) * cellSpacing - sumPref;
+ float factor = 0.0F;
+ int[] diffs = null;
+ if (diff != 0)
+ {
+ long total = 0;
+ diffs = new int[n];
+ for (int i = 0; i < n; i++)
+ {
+ // Only adjust the width if we haven't set a column width here.
+ if (columnWidths[i] == null)
+ {
+ SizeRequirements col = columnRequirements[i];
+ int span;
+ if (diff < 0)
+ {
+ span = col.minimum;
+ diffs[i] = columnSpans[i] - span;
+ }
+ else
+ {
+ span = col.maximum;
+ diffs[i] = span - columnSpans[i];
+ }
+ total += span;
+ }
+ else
+ total += columnSpans[i];
+ }
+
+ float maxAdjust = Math.abs(total - sumPref);
+ factor = diff / maxAdjust;
+ factor = Math.min(factor, 1.0F);
+ factor = Math.max(factor, -1.0F);
+ }
+
+ // Actually perform adjustments.
+ int totalOffs = cellSpacing;
+ for (int i = 0; i < n; i++)
+ {
+ columnOffsets[i] = totalOffs;
+ if (diff != 0)
+ {
+ float adjust = factor * diffs[i];
+ columnSpans[i] += Math.round(adjust);
+ }
+ // Avoid overflow here.
+ totalOffs = (int) Math.min((long) totalOffs + (long) columnSpans[i]
+ + (long) cellSpacing, Integer.MAX_VALUE);
+ }
+ }
+
+ /**
+ * Updates the arrays that contain the row and column data in response
+ * to a change to the table structure.
+ *
+ * Package private to avoid accessor methods.
+ */
+ void updateGrid()
+ {
+ if (! gridValid)
+ {
+ AttributeSet atts = getAttributes();
+ StyleSheet ss = getStyleSheet();
+ float emBase = ss.getEMBase(atts);
+ float exBase = ss.getEXBase(atts);
+ int maxColumns = 0;
+ int numRows = getViewCount();
+ for (int r = 0; r < numRows; r++)
+ {
+ View rowView = getView(r);
+ int numCols = 0;
+ if (rowView instanceof RowView)
+ {
+ int numCells = ((RowView) rowView).getViewCount();
+ for (int i = 0; i < numCells; i++)
+ {
+ View v = rowView.getView(i);
+ if (v instanceof CellView)
+ numCols += ((CellView) v).colSpan;
+ }
+ }
+ maxColumns = Math.max(numCols, maxColumns);
+ }
+ numColumns = maxColumns;
+ columnWidths = new Length[maxColumns];
+ int[] rowSpans = new int[maxColumns];
+ for (int r = 0; r < numRows; r++)
+ {
+ View view = getView(r);
+ if (view instanceof RowView)
+ {
+ RowView rowView = (RowView) view;
+ rowView.rowIndex = r;
+ rowView.overlap = new boolean[maxColumns];
+ int colIndex = 0;
+ int colCount = rowView.getViewCount();
+ for (int c = 0; c < maxColumns;)
+ {
+ if (rowSpans[c] > 0)
+ {
+ rowSpans[c]--;
+ rowView.overlap[c] = true;
+ c++;
+ }
+ else if (colIndex < colCount)
+ {
+ View v = rowView.getView(colIndex);
+ colIndex++;
+ if (v instanceof CellView)
+ {
+ CellView cv = (CellView) v;
+ Object o =
+ cv.getAttributes().getAttribute(CSS.Attribute.WIDTH);
+ if (o != null && columnWidths[c] == null
+ && o instanceof Length)
+ {
+ columnWidths[c]= (Length) o;
+ columnWidths[c].setFontBases(emBase, exBase);
+ }
+ int rs = cv.rowSpan - 1;
+ for (int col = cv.colSpan - 1; col >= 0; col--)
+ {
+ rowSpans[c] = rs;
+ c++;
+ }
+ }
+ }
+ else
+ {
+ c++;
+ }
+ }
+ }
+ }
+ columnRequirements = new SizeRequirements[maxColumns];
+ for (int i = 0; i < maxColumns; i++)
+ columnRequirements[i] = new SizeRequirements();
+ columnOffsets = new int[maxColumns];
+ columnSpans = new int[maxColumns];
+
+ gridValid = true;
+ }
+ }
+
+ /**
+ * Overridden to restrict the table width to the preferred size.
+ */
+ public float getMaximumSpan(int axis)
+ {
+ float span;
+ if (axis == X_AXIS)
+ span = super.getPreferredSpan(axis);
+ else
+ span = super.getMaximumSpan(axis);
+ return span;
+ }
+
+ /**
+ * Overridden to fetch the CSS attributes when view gets connected.
+ */
+ public void setParent(View parent)
+ {
+ super.setParent(parent);
+ if (parent != null)
+ setPropertiesFromAttributes();
+ }
+
+ /**
+ * Fetches CSS and HTML layout attributes.
+ */
+ protected void setPropertiesFromAttributes()
+ {
+ super.setPropertiesFromAttributes();
+
+ // Fetch and parse cell spacing.
+ AttributeSet atts = getAttributes();
+ StyleSheet ss = getStyleSheet();
+ float emBase = ss.getEMBase(atts);
+ float exBase = ss.getEXBase(atts);
+ Object o = atts.getAttribute(CSS.Attribute.BORDER_SPACING);
+ if (o != null && o instanceof Length)
+ {
+ Length l = (Length) o;
+ l.setFontBases(emBase, exBase);
+ cellSpacing = (int) l.getValue();
+ }
+ o = atts.getAttribute(CSS.Attribute.WIDTH);
+ if (o != null && o instanceof Length)
+ {
+ width = (Length) o;
+ width.setFontBases(emBase, exBase);
+ }
+ }
+
+ /**
+ * Overridden to adjust for cellSpacing.
+ */
+ protected SizeRequirements calculateMajorAxisRequirements(int axis,
+ SizeRequirements r)
+ {
+ r = super.calculateMajorAxisRequirements(axis, r);
+ int adjust = (getViewCount() + 1) * cellSpacing;
+ r.minimum += adjust;
+ r.preferred += adjust;
+ r.maximum += adjust;
+ return r;
+ }
+
+ /**
+ * Overridden to adjust for cellSpacing.
+ */
+ protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
+ int spans[])
+ {
+ // Mark all rows as invalid along their minor axis to force correct
+ // layout of multi-row cells.
+ int n = getViewCount();
+ for (int i = 0; i < n; i++)
+ {
+ View row = getView(i);
+ if (row instanceof RowView)
+ ((RowView) row).layoutChanged(axis);
+ }
+
+ int adjust = (getViewCount() + 1) * cellSpacing;
+ super.layoutMajorAxis(targetSpan - adjust, axis, offsets, spans);
+ for (int i = 0; i < offsets.length; i++)
+ {
+ offsets[i] += (i + 1) * cellSpacing;
+ }
+ }
+
+ /**
+ * Overridden to replace view factory with this one.
+ */
+ public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f)
+ {
+ super.insertUpdate(e, a, this);
+ }
+
+ /**
+ * Overridden to replace view factory with this one.
+ */
+ public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f)
+ {
+ super.removeUpdate(e, a, this);
+ }
+
+ /**
+ * Overridden to replace view factory with this one.
+ */
+ public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f)
+ {
+ super.changedUpdate(e, a, this);
+ }
+
+ public void replace(int offset, int len, View[] views)
+ {
+ gridValid = false;
+ super.replace(offset, len, views);
+ }
+
+ /**
+ * We can't use the super class's paint() method because it might cut
+ * off multi-row children. Instead we trigger painting for all rows
+ * and let the rows sort out what to paint and what not.
+ */
+ public void paint(Graphics g, Shape a)
+ {
+ Rectangle rect = a instanceof Rectangle ? (Rectangle) a : a.getBounds();
+ painter.paint(g, rect.x, rect.y, rect.width, rect.height, this);
+ int nRows = getViewCount();
+ Rectangle inside = getInsideAllocation(a);
+ for (int r = 0; r < nRows; r++)
+ {
+ tmpRect.setBounds(inside);
+ childAllocation(r, tmpRect);
+ paintChild(g, tmpRect, r);
+ }
+ }
+
+}
diff --git a/libjava/classpath/javax/swing/text/html/ViewAttributeSet.java b/libjava/classpath/javax/swing/text/html/ViewAttributeSet.java
new file mode 100644
index 000000000..fb57872ce
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/ViewAttributeSet.java
@@ -0,0 +1,163 @@
+/* ViewAttributeSet.java -- The AttributeSet used by HTML views
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+
+import javax.swing.text.AttributeSet;
+import javax.swing.text.Element;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.View;
+
+/**
+ * An AttributeSet implemenation that is used by the HTML views. This
+ * AttributeSet is created by StyleSheet.getViewAttributes() and combines
+ * the following attributes:
+ * - The original attributes of the View's element.
+ * - Any translated (HTML->CSS) attributes, as returned by
+ * StyleSheet.translateHTMLToCS().
+ * - CSS Styles as resolved by the CSS stylesheet.
+ *
+ * In addition to that, it resolves attributes to the parent views, if
+ * a CSS attribute is requested that is inheritable.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+class ViewAttributeSet
+ extends MultiAttributeSet
+{
+
+ /**
+ * The view for which we are the AttributeSet.
+ */
+ private View view;
+
+ /**
+ * The stylesheet to use.
+ */
+ private StyleSheet styleSheet;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param v the view for which to do the AttributeSet
+ */
+ ViewAttributeSet(View v, StyleSheet ss)
+ {
+ styleSheet = ss;
+ view = v;
+ ArrayList<AttributeSet> atts = new ArrayList<AttributeSet>();
+
+ Element el = v.getElement();
+ AttributeSet elAtts = el.getAttributes();
+ AttributeSet htmlAtts = styleSheet.translateHTMLToCSS(elAtts);
+ if (htmlAtts.getAttributeCount() > 0)
+ atts.add(htmlAtts);
+
+ if (el.isLeaf())
+ {
+ Enumeration<?> n = elAtts.getAttributeNames();
+ while (n.hasMoreElements())
+ {
+ Object key = n.nextElement();
+ if (key instanceof HTML.Tag)
+ {
+ AttributeSet rule = styleSheet.getRule((HTML.Tag) key, el);
+ if (rule != null)
+ atts.add(rule);
+ }
+ }
+ }
+ else
+ {
+ HTML.Tag tag =
+ (HTML.Tag) elAtts.getAttribute(StyleConstants.NameAttribute);
+ AttributeSet rule = styleSheet.getRule(tag, el);
+ if (rule != null)
+ atts.add(rule);
+ }
+
+ AttributeSet[] atts1 = new AttributeSet[atts.size()];
+ atts1 = atts.toArray(atts1);
+ init(atts1);
+ }
+
+ /**
+ * Fetches the attribute for the specific ckey. If the attribute
+ * can't be found and the key is a CSS.Attribute that is inherited,
+ * then the attribute is looked up in the resolve parent.
+ */
+ public Object getAttribute(Object key)
+ {
+ Object val = super.getAttribute(key);
+ if (val == null)
+ {
+ // Didn't find value. If the key is a CSS.Attribute, and is
+ // inherited, then ask the resolve parent.
+ if (key instanceof CSS.Attribute)
+ {
+ CSS.Attribute cssKey = (CSS.Attribute) key;
+ if (cssKey.isInherited())
+ {
+ AttributeSet resolveParent = getResolveParent();
+ if (resolveParent != null)
+ val = resolveParent.getAttribute(cssKey);
+ }
+ }
+ }
+ return val;
+ }
+
+ /**
+ * Returns the resolve parent of this AttributeSet. This is the AttributeSet
+ * returned by the parent view if available.
+ */
+ public AttributeSet getResolveParent()
+ {
+ AttributeSet parent = null;
+ if (view != null)
+ {
+ View parentView = view.getParent();
+ if (parentView != null)
+ parent = parentView.getAttributes();
+ }
+ return parent;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/package.html b/libjava/classpath/javax/swing/text/html/package.html
new file mode 100644
index 000000000..c7e774428
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/package.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in javax.swing.text.html package.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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. -->
+
+<html>
+<head><title>GNU Classpath - javax.swing.text.html</title></head>
+
+<body>
+<p> Provides supporting classes for web browsers,
+ web robots, web page content analysers, web editors and
+ other applications applications working with Hypertext
+ Markup Language (HTML).
+</p>
+
+</body>
+</html>
diff --git a/libjava/classpath/javax/swing/text/html/parser/AttributeList.java b/libjava/classpath/javax/swing/text/html/parser/AttributeList.java
new file mode 100644
index 000000000..a943f056d
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/parser/AttributeList.java
@@ -0,0 +1,294 @@
+/* AttributeList.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html.parser;
+
+import gnu.javax.swing.text.html.parser.support.gnuStringIntMapper;
+
+import java.io.Serializable;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * <p>
+ * Stores the attribute information, obtained by parsing SGML (DTD) tag
+ * <code>&lt;!ATTLIST .. &gt;</code></p>
+ * <p>
+ * Elements can have a associated named properties (attributes) having the
+ * assigned values. The element start tag can have any number of attribute
+ * value pairs, separated by spaces. They can appear in any order.
+ * SGML requires you to delimit the attribute values using either double (")
+ * or single (') quotation marks. In HTML, it is possible
+ * (but not recommended) to specify the value of an attribute without
+ * quotation marks. Such attribute value may only contain
+ * letters, digits, hyphens (-) and periods (.) .
+ * </p>
+ * <p>
+ * The <code>AttributeList</code> defines a single attribute that additionally
+ * has a pointer referencing the possible subsequent attribute.
+ * The whole structure is just a simple linked list, storing all attributes of
+ * some <code>Element</code>.
+ * Use the <code>getNext()</code> method repeatedly to see all attributes in
+ * the list.
+ * </p>
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public final class AttributeList
+ implements DTDConstants, Serializable
+{
+ /** Maps between type names and they string values. */
+ private static final gnuStringIntMapper mapper =
+ new gnuStringIntMapper()
+ {
+ protected void create()
+ {
+ add("CDATA", DTDConstants.CDATA);
+ add("ENTITY", DTDConstants.ENTITY);
+ add("ENTITIES", DTDConstants.ENTITIES);
+ add("ID", DTDConstants.ID);
+ add("IDREF", DTDConstants.IDREF);
+ add("IDREFS", DTDConstants.IDREFS);
+ add("NAME", DTDConstants.NAME);
+ add("NAMES", DTDConstants.NAMES);
+ add("NMTOKEN", DTDConstants.NMTOKEN);
+ add("NMTOKENS", DTDConstants.NMTOKENS);
+ add("NOTATION", DTDConstants.NOTATION);
+ add("NUMBER", DTDConstants.NUMBER);
+ add("NUMBERS", DTDConstants.NUMBERS);
+ add("NUTOKEN", DTDConstants.NUTOKEN);
+ add("NUTOKENS", DTDConstants.NUTOKENS);
+ }
+ };
+
+ /** Use serialVersionUID for interoperability. */
+ private static final long serialVersionUID = -1361214058742015233L;
+
+ /**
+ * The value of ( = pointer to ) the next attribute in the linked list,
+ * storing all attributes of some Element. Contains null for the
+ * last attribute.
+ */
+ public AttributeList next;
+
+ /**
+ * The name of the attribute. The attribute names are case insensitive.
+ */
+ public String name;
+
+ /**
+ * The default value of this attribute. Equals to null if no default value
+ * is specified.
+ */
+ public String value;
+
+ /**
+ * The explicit set of the allowed values of this attribute. Equals to
+ * null, if this parameter was not specified.
+ * Values, defined in DTD, are case insensitive.
+ */
+ public Vector<?> values;
+
+ /**
+ * The modifier of this attribute. This field contains one of the
+ * following DTD constants:
+ * <ul>
+ * <li> REQUIRED if the attribute value is always required,</li>
+ * <li> IMPLIED if the user agent must supply the default value itself,</li>
+ * <li> FIXED if the attribute value is fixed to some value and cannot
+ * be changed.</li>
+ * <li> DEFAULT if the attribute default value has been supplied.</li>
+ * <li> CURRENT the value that at any point in the document is
+ * the last value supplied for that element. A value is required to be
+ * supplied for the first* occurrence of an element</li>
+ * <li> CONREF specifies the IDREF value of
+ * the reference to content in another location of the document.
+ * The element with this attribute is empty, the content from
+ * that another location must be used instead.</li>
+ * </ul>
+ */
+ public int modifier;
+
+ /**
+ * The type of the attribute. The possible values of this field
+ * (NUMBER, NAME, ID, CDATA and so on) are defined in DTDConstants.
+ */
+ public int type;
+
+ /**
+ * Creates the attribute with the given name, initializing other fields
+ * to the default values ( 0 and null ).
+ *
+ * @param a_name The name of the attribute.
+ */
+ public AttributeList(String a_name)
+ {
+ name = a_name;
+ }
+
+ /**
+ * Creates the attribute with the given properties.
+ * @param a_name The name of the attribute
+ * @param a_type The type of the attribute. The possible values are defined
+ * in <code> DTDConstants</code>.
+ * @param a_modifier The modifier of this attribute. The possible values
+ * are defined in <code> DTDConstants</code>.
+ * @param a_default The default value of this attribute
+ * @param allowed_values The explicit set of the allowed values of
+ * this attribute
+ * @param a_next The value of the subsequent instance of the AttributeList,
+ * representing the next attribute definition for the same element.
+ * Equals to null for the last attribute definition.
+ */
+ public AttributeList(String a_name, int a_type, int a_modifier,
+ String a_default, Vector<?> allowed_values,
+ AttributeList a_next
+ )
+ {
+ this(a_name);
+ type = a_type;
+ modifier = a_modifier;
+ value = a_default;
+ values = allowed_values;
+ next = a_next;
+ }
+
+ /**
+ * Get the modifier of this attribute. This field contains one of the
+ * following DTD constants:
+ * <ul>
+ * <li> REQUIRED if the attribute value is always required,</li>
+ * <li> IMPLIED if the user agent must supply the default value itself,</li>
+ * <li> FIXED if the attribute value is fixed to some value and cannot
+ * be changed.</li>
+ * <li> DEFAULT if the attribute default value has been supplied.</li>
+ * <li> CURRENT the value that at any point in the document is
+ * the last value supplied for that element. A value is required to be
+ * supplied for the first* occurrence of an element</li>
+ * <li> CONREF specifies the IDREF value of
+ * the reference to content in another location of the document.
+ * The element with this attribute is empty, the content from
+ * that another location must be used instead.</li>
+ * </ul>
+ */
+ public int getModifier()
+ {
+ return modifier;
+ }
+
+ /**
+ * Get the name of the attribute.
+ * The value is returned as it was supplied to a
+ * constructor, preserving the character case.
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Get the value of ( = pointer to ) the next attribute in the linked list,
+ * storing all attributes of some Element. Contains null for the
+ * last attribute.
+ */
+ public AttributeList getNext()
+ {
+ return next;
+ }
+
+ /**
+ * Get the type of the attribute. The possible values of this field
+ * (NUMBER, NAME, ID, CDATA and so on) are defined in DTDConstants.
+ */
+ public int getType()
+ {
+ return type;
+ }
+
+ /**
+ * Get the default value of this attribute.
+ */
+ public String getValue()
+ {
+ return value;
+ }
+
+ /**
+ * Get the allowed values of this attribute.
+ */
+ public Enumeration<?> getValues()
+ {
+ return (values != null) ? values.elements() : null;
+ }
+
+ /**
+ * Converts a string value, representing a valid SGLM attribute type,
+ * into the corresponding value, defined in DTDConstants.
+ * @param typeName the name of the type (character case is ignored).
+ * @return a value from DTDConstants or DTDConstants.ANY if the
+ * string is not representing a known type. The known attribute types
+ * in this implementation are CDATA, ENTITY, ENTITIES, ID, IDREF, IDREFS,
+ * NAME, NAMES, NMTOKEN, NMTOKENS, NOTATION, NUMBER, NUMBERS, NUTOKEN and
+ * NUTOKENS.
+ * @throws NullPointerException if the passed parameter is null.
+ */
+ public static int name2type(String typeName)
+ {
+ return mapper.get(typeName.toUpperCase());
+ }
+
+ /**
+ * Returns the attribute name.
+ */
+ public String toString()
+ {
+ return name;
+ }
+
+ /**
+ * Converts a value from DTDConstants into the string representation.
+ * @param type - an integer value of the public static integer field,
+ * defined in the DTDConstants class.
+ * @return a corresponding SGML DTD keyword (UPPERCASE) or null if there
+ * are no attribute type constant having the given value.
+ */
+ public static String type2name(int type)
+ {
+ return mapper.get(type);
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/parser/ContentModel.java b/libjava/classpath/javax/swing/text/html/parser/ContentModel.java
new file mode 100644
index 000000000..d5c4418de
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/parser/ContentModel.java
@@ -0,0 +1,223 @@
+/* ContentModel.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html.parser;
+
+import gnu.javax.swing.text.html.parser.models.transformer;
+
+import java.io.Serializable;
+
+import java.util.Vector;
+
+/**
+ * A representation of the element content. The instances of this class
+ * can be arranged into the linked list, representing a BNF expression.
+ * The content model is constructed as a branched tree structure in the
+ * following way:
+ * <pre>
+ * a = new ContentModel('+', A, null); // a reprensents A+
+ * b = new ContentModel('&amp;', B, a); // b represents B &amp; A+
+ * c = new ContentModel('*', b, null); // c represents ( B &amp; A+) *
+ * d = new ContentModel('|', new ContentModel('*', A, null),
+ * new ContentModel('?', B, null)); // d represents ( A* | B? )
+ * </pre>
+ * where the valid operations are:
+ * <ul>
+ * <li><code>E* </code> E occurs zero or more times</li>
+ * <li><code>E+ </code> E occurs one or more times</li>
+ * <li><code>E? </code> E occurs once or not atl all</li>
+ * <li><code>A,B</code> A occurs before B</li>
+ * <li><code>A|B</code> both A and B are permitted in any order.
+ * The '|' alone does not permit the repetetive occurence of A or B
+ * (use <code>(A|B)*</code>.</li>
+ * <li><code>A&amp;B</code> both A and B must occur once (in any order)</li>
+ * </ul>
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public final class ContentModel
+ implements Serializable
+{
+ /** Use serialVersionUID for interoperability. */
+ private static final long serialVersionUID = -1130825523866321257L;
+
+ /**
+ * The next content model model ( = pointer to the next element of
+ * the linked list) for the binary expression (',','&amp;' or '|'). Null
+ * for the last element in the list.
+ */
+ public ContentModel next;
+
+ /**
+ * The document content, containing either Element or the enclosed
+ * content model (that would be in the parentheses in BNF expression).
+ */
+ public Object content;
+
+ /**
+ * Specifies the BNF operation between this node and the node,
+ * stored in the field <code>next</code> (or for this node, if it is
+ * an unary operation.
+ */
+ public int type;
+
+ /**
+ * Create a content model initializing all fields to default values.
+ */
+ public ContentModel()
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Create a content model, consisting of the single element.
+ * Examples:
+ *<code>
+ * a = new ContentModel('+', A, null); // a reprensents A+
+ * b = new ContentModel('&amp;', B, a); // b represents B &amp; A+
+ * c = new ContentModel('*', b, null); // c represents ( B &amp; A+) *
+ * d = new ContentModel('|', A,
+ * new ContentModel('?',b, null);
+ * // d represents
+ * </code>
+ */
+ public ContentModel(Element a_content)
+ {
+ content = a_content;
+ }
+
+ /**
+ * Create a content model, involving expression of the given type.
+ * @param a_type The expression operation type ('*','?' or '+'
+ * @param a_content The content for that the expression is applied.
+ */
+ public ContentModel(int a_type, ContentModel a_content)
+ {
+ content = a_content;
+ type = a_type;
+ }
+
+ /**
+ * Create a content model, involving binary expression of the given type.
+ * @param a_type The expression operation type ( ',', '|' or '&amp;').
+ * @param a_content The content of the left part of the expression.
+ * @param a_next The content model, representing the right part of the
+ * expression.
+ */
+ public ContentModel(int a_type, Object a_content, ContentModel a_next)
+ {
+ content = a_content;
+ type = a_type;
+ next = a_next;
+ }
+
+ /**
+ * Adds all list elements to the given vector, ignoring the
+ * operations between the elements. The old vector values are not
+ * discarded.
+ * @param elements - a vector to add the values to.
+ */
+ public void getElements(Vector<Element> elements)
+ {
+ ContentModel c = this;
+
+ while (c != null)
+ {
+ // FIXME: correct?
+ if (c.content instanceof Element)
+ elements.add((Element) c.content);
+ c = c.next;
+ }
+ }
+
+ /**
+ * Checks if the content model matches an empty input stream.
+ * The empty content is created using SGML DTD keyword EMPTY.
+ * The empty model is a model with the content field equal to null.
+ *
+ * @return true if the content field is equal to null.
+ */
+ public boolean empty()
+ {
+ return content == null;
+ }
+
+ /**
+ * Get the element, stored in the <code>next.content</code>.
+ * The method is programmed as the part of the standard API, but not
+ * used in this implementation.
+ * @return the value of the field <code>next</code>.
+ */
+ public Element first()
+ {
+ return (Element) next.content;
+ }
+
+ /**
+ * Checks if this object can potentially be the first token in the
+ * ContenModel list. The method is programmed as the part of the
+ * standard API, but not used in this implementation.
+ */
+ public boolean first(Object token)
+ {
+ ContentModel c = this;
+ while (c.next != null)
+ {
+ if (c.content != null && c.content.toString().equals(token.toString()) &&
+ c.type != ','
+ )
+
+ // Agree if the operation with the preceeding element
+ // is not the comma operation.
+ return true;
+ c = c.next;
+ }
+ return false;
+ }
+
+ /**
+ * Returns a string representation (an expression) of this content model.
+ * The expression has BNF-like syntax, except the absence of the
+ * unary operator is additionally indicated by " ' ". It is
+ * advisable to check the created models for correctness using this
+ * method.
+ */
+ public String toString()
+ {
+ return transformer.transform(this).toString();
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/parser/DTD.java b/libjava/classpath/javax/swing/text/html/parser/DTD.java
new file mode 100644
index 000000000..09b50fee7
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/parser/DTD.java
@@ -0,0 +1,609 @@
+/* DTD.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html.parser;
+
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.BitSet;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+/**
+ * <p>Representation or the SGML DTD document.
+ * Provides basis for describing a syntax of the
+ * HTML documents. The fields of this class are NOT initialized in
+ * constructor. You need to do this separately before passing this data
+ * structure to the HTML parser. The subclasses with the fields, pre-
+ * initialized, for example, for HTML 4.01, can be available only between
+ * the implementation specific classes
+ * ( for example, {@link gnu.javax.swing.text.html.parser.HTML_401F }
+ * in this implementation).</p>
+ * <p>
+ * If you need more information about SGML DTD documents,
+ * the author suggests to read SGML tutorial on
+ * <a href="http://www.w3.org/TR/WD-html40-970708/intro/sgmltut.html"
+ * >http://www.w3.org/TR/WD-html40-970708/intro/sgmltut.html</a>.
+ * We also recommend Goldfarb C.F (1991) <i>The SGML Handbook</i>,
+ * Oxford University Press, 688 p, ISBN: 0198537379.
+ * </p>
+ * <p>
+ * Warning: the html, head and other tag fields will only be automatically
+ * assigned if the VM has the correctly implemented reflection mechanism.
+ * As these fields are not used anywhere in the implementation, not
+ * exception will be thrown in the opposite case.
+ * </p>
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class DTD
+ implements DTDConstants
+{
+ /**
+ * The version of the persistent data format.
+ * @specnote This was made <code>final</code> in 1.5.
+ */
+ public static final int FILE_VERSION = 1;
+
+ /**
+ * The table of existing available DTDs.
+ */
+ static Hashtable<String,DTD> dtdHash = new Hashtable<String,DTD>();
+
+ /**
+ * The applet element for this DTD.
+ */
+ public Element applet;
+
+ /**
+ * The base element for this DTD.
+ */
+ public Element base;
+
+ /**
+ * The body element for this DTD.
+ */
+ public Element body;
+
+ /**
+ * The head element for this DTD.
+ */
+ public Element head;
+
+ /**
+ * The html element for this DTD.
+ */
+ public Element html;
+
+ /**
+ * The isindex element of for this DTD.
+ */
+ public Element isindex;
+
+ /**
+ * The meta element for this DTD.
+ */
+ public Element meta;
+
+ /**
+ * The p element for this DTD.
+ */
+ public Element p;
+
+ /**
+ * The param element for this DTD.
+ */
+ public Element param;
+
+ /**
+ * The pcdata for this DTD.
+ */
+ public Element pcdata;
+
+ /**
+ * The title element for this DTD.
+ */
+ public Element title;
+
+ /**
+ * The element for accessing all DTD elements by name.
+ */
+ public Hashtable<String,Element> elementHash =
+ new Hashtable<String,Element>();
+
+ /**
+ * The entity table for accessing all DTD entities by name.
+ */
+ public Hashtable<Object, Entity> entityHash = new Hashtable<Object, Entity>();
+
+ /**
+ * The name of this DTD.
+ */
+ public String name;
+
+ /**
+ * Contains all elements in this DTD. The
+ * javax.swing.text.html.parser.Element#index field of all elements
+ * in this vector is set to the element position in this vector.
+ */
+ public Vector<Element> elements = new Vector<Element>();
+
+ /** Create a new DTD with the specified name. */
+ protected DTD(String a_name)
+ {
+ name = a_name;
+ }
+
+ /** Get this DTD by name. The current implementation
+ * only looks in the internal table of DTD documents. If no corresponding
+ * entry is found, the new entry is created, placed into
+ * the table and returned. */
+ public static DTD getDTD(String name)
+ throws IOException
+ {
+ DTD d = dtdHash.get(name);
+
+ if (d == null)
+ {
+ d = new DTD(name);
+ dtdHash.put(d.name, d);
+ }
+
+ return d;
+ }
+
+ /**
+ * Get the element by the element name. If the element is not yet
+ * defined, it is newly created and placed into the element table.
+ * If the element name matches (ingoring case) a public non static
+ * element field in this class, this field is assigned to the value
+ * of the newly created element.
+ */
+ public Element getElement(String element_name)
+ {
+ return newElement(element_name);
+ }
+
+ /**
+ * Get the element by the value of its
+ * {@link javax.swing.text.html.parser.Element#index} field.
+ */
+ public Element getElement(int index)
+ {
+ return elements.get(index);
+ }
+
+ /**
+ * Get the entity with the given identifier.
+ * @param id that can be returned by
+ * {@link javax.swing.text.html.parser.Entity#name2type(String an_entity)}
+ * @return The entity from this DTD or null if there is no entity with
+ * such id or such entity is not present in the table of this instance.
+ */
+ public Entity getEntity(int id)
+ {
+ String name = Entity.mapper.get(id);
+
+ if (name != null)
+ return entityHash.get(name);
+ else
+ return null;
+ }
+
+ /**
+ * Get the named entity by its name.
+ */
+ public Entity getEntity(String entity_name)
+ {
+ return entityHash.get(entity_name);
+ }
+
+ /**
+ * Get the name of this instance of DTD
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Creates, adds into the entity table and returns the
+ * character entity like <code>&amp;lt;</code>
+ * (means '<code>&lt;</code>' );
+ * @param name The entity name (without heading &amp; and closing ;)
+ * @param type The entity type
+ * @param character The entity value (single character)
+ * @return The created entity
+ */
+ public Entity defEntity(String name, int type, int character)
+ {
+ Entity e = newEntity(name, type);
+ e.data = new char[] { (char) character };
+ return e;
+ }
+
+ /**
+ * Define the attributes for the element with the given name.
+ * If the element is not exist, it is created.
+ * @param forElement
+ * @param attributes
+ */
+ public void defineAttributes(String forElement, AttributeList attributes)
+ {
+ Element e = elementHash.get(forElement.toLowerCase());
+
+ if (e == null)
+ e = newElement(forElement);
+
+ e.atts = attributes;
+ }
+
+ /**
+ * Defines the element and adds it to the element table. Sets the
+ * <code>Element.index</code> field to the value, unique for this
+ * instance of DTD. If the element with the given name already exists,
+ * replaces all other its settings by the method argument values.
+ * @param name the name of the element
+ * @param type the type of the element
+ * @param headless true if the element needs no starting tag
+ * (should not occur in HTML).
+ * @param tailless true if the element needs no ending tag (like
+ * <code>&lt;hr&gt;</code>
+ * @param content the element content
+ * @param exclusions the set of elements that must not occur inside
+ * this element. The <code>Element.index</code> value defines which
+ * bit in this bitset corresponds to that element.
+ * @param inclusions the set of elements that can occur inside this
+ * element. the <code>Element.index</code> value defines which
+ * bit in this bitset corresponds to that element.
+ * @param attributes the element attributes.
+ * @return the newly defined element.
+ */
+ public Element defineElement(String name, int type, boolean headless,
+ boolean tailless, ContentModel content,
+ BitSet exclusions, BitSet inclusions,
+ AttributeList attributes
+ )
+ {
+ Element e = newElement(name);
+ e.type = type;
+ e.oStart = headless;
+ e.oEnd = tailless;
+ e.content = content;
+ e.exclusions = exclusions;
+ e.inclusions = inclusions;
+ e.atts = attributes;
+
+ return e;
+ }
+
+ /**
+ * Creates, intializes and adds to the entity table the new
+ * entity.
+ * @param name the name of the entity
+ * @param type the type of the entity
+ * @param data the data section of the entity
+ * @return the created entity
+ */
+ public Entity defineEntity(String name, int type, char[] data)
+ {
+ Entity e = newEntity(name, type);
+ e.data = data;
+
+ return e;
+ }
+
+ /** Place this DTD into the DTD table. */
+ public static void putDTDHash(String name, DTD dtd)
+ {
+ dtdHash.put(name, dtd);
+ }
+
+ /**
+ * <p>Reads DTD from an archived format. This format is not standardized
+ * and differs between implementations.</p><p> This implementation
+ * reads and defines all entities and elements using
+ * ObjectInputStream. The elements and entities can be written into the
+ * stream in any order. The objects other than elements and entities
+ * are ignored.</p>
+ * @param stream A data stream to read from.
+ * @throws java.io.IOException If one is thrown by the input stream
+ */
+ public void read(DataInputStream stream)
+ throws java.io.IOException
+ {
+ ObjectInputStream oi = new ObjectInputStream(stream);
+ Object def;
+ try
+ {
+ while (true)
+ {
+ def = oi.readObject();
+ if (def instanceof Element)
+ {
+ Element e = (Element) def;
+ elementHash.put(e.name.toLowerCase(), e);
+ assignField(e);
+ }
+ else if (def instanceof Entity)
+ {
+ Entity e = (Entity) def;
+ entityHash.put(e.name, e);
+ }
+ }
+ }
+ catch (ClassNotFoundException ex)
+ {
+ throw new IOException(ex.getMessage());
+ }
+ catch (EOFException ex)
+ {
+ // ok EOF
+ }
+ }
+
+ /**
+ * Returns the name of this instance of DTD.
+ */
+ public String toString()
+ {
+ return name;
+ }
+
+ /**
+ * Creates and returns new attribute (not an attribute list).
+ * @param name the name of this attribute
+ * @param type the type of this attribute (FIXED, IMPLIED or
+ * REQUIRED from <code>DTDConstants</code>).
+ * @param modifier the modifier of this attribute
+ * @param default_value the default value of this attribute
+ * @param allowed_values the allowed values of this attribute. The multiple
+ * possible values in this parameter are supposed to be separated by
+ * '|', same as in SGML DTD <code>&lt;!ATTLIST </code>tag. This parameter
+ * can be null if no list of allowed values is specified.
+ * @param atts the previous attribute of this element. This is
+ * placed to the field
+ * {@link javax.swing.text.html.parser.AttributeList#next },
+ * creating a linked list.
+ * @return The attributes.
+ */
+ protected AttributeList defAttributeList(String name, int type, int modifier,
+ String default_value,
+ String allowed_values,
+ AttributeList atts
+ )
+ {
+ AttributeList al = new AttributeList(name);
+ al.modifier = modifier;
+ al.value = default_value;
+ al.next = atts;
+
+ if (allowed_values != null)
+ {
+ StringTokenizer st = new StringTokenizer(allowed_values, " \t|");
+ Vector<String> v = new Vector<String>(st.countTokens());
+
+ while (st.hasMoreTokens())
+ v.add(st.nextToken());
+
+ al.values = v;
+ }
+
+ return al;
+ }
+
+ /**
+ * Creates a new content model.
+ * @param type specifies the BNF operation for this content model.
+ * The valid operations are documented in the
+ * {@link javax.swing.text.html.parser.ContentModel#type }.
+ * @param content the content of this content model
+ * @param next if the content model is specified by BNF-like
+ * expression, contains the rest of this expression.
+ * @return The newly created content model.
+ */
+ protected ContentModel defContentModel(int type, Object content,
+ ContentModel next
+ )
+ {
+ ContentModel model = new ContentModel();
+ model.type = type;
+ model.next = next;
+ model.content = content;
+
+ return model;
+ }
+
+ /**
+ * Defines a new element and adds it to the element table.
+ * If the element alredy exists,
+ * overrides it settings with the specified values.
+ * @param name the name of the new element
+ * @param type the type of the element
+ * @param headless true if the element needs no starting tag
+ * @param tailless true if the element needs no closing tag
+ * @param content the element content.
+ * @param exclusions the elements that must be excluded from the
+ * content of this element, in all levels of the hierarchy.
+ * @param inclusions the elements that can be included as the
+ * content of this element.
+ * @param attributes the element attributes.
+ * @return the created or updated element.
+ */
+ protected Element defElement(String name, int type, boolean headless,
+ boolean tailless, ContentModel content,
+ String[] exclusions, String[] inclusions,
+ AttributeList attributes
+ )
+ {
+ // compute the bit sets
+ BitSet exclude = bitSet(exclusions);
+ BitSet include = bitSet(inclusions);
+
+ Element e =
+ defineElement(name, type, headless, tailless, content, exclude, include,
+ attributes
+ );
+
+ return e;
+ }
+
+ /**
+ * Creates, intializes and adds to the entity table the new
+ * entity.
+ * @param name the name of the entity
+ * @param type the type of the entity
+ * @param data the data section of the entity
+ * @return the created entity
+ */
+ protected Entity defEntity(String name, int type, String data)
+ {
+ Entity e = newEntity(name, type);
+ e.data = data.toCharArray();
+
+ return e;
+ }
+
+ private void assignField(Element e)
+ {
+ String element_name = e.name;
+ try
+ {
+ // Assign the field via reflection.
+ Field f = getClass().getField(element_name.toLowerCase());
+ if ((f.getModifiers() & Modifier.PUBLIC) != 0)
+ if ((f.getModifiers() & Modifier.STATIC) == 0)
+ if (f.getType().isAssignableFrom(e.getClass()))
+ f.set(this, e);
+ }
+ catch (IllegalAccessException ex)
+ {
+ unexpected(ex);
+ }
+ catch (NoSuchFieldException ex)
+ {
+ // This is ok.
+ }
+
+ // Some virtual machines may still lack the proper
+ // implementation of reflection. As the tag fields
+ // are not used anywhere in this implementation,
+ // (and this class is also rarely used by the end user),
+ // it may be better not to crash everything by throwing an error
+ // for each case when the HTML parsing is required.
+ catch (Throwable t)
+ {
+ // This VM has no reflection mechanism implemented!
+ if (t instanceof OutOfMemoryError)
+ throw (Error) t;
+ }
+ }
+
+ /**
+ * Create the bit set for this array of elements.
+ * The unknown elements are automatically defined and added
+ * to the element table.
+ * @param elements
+ * @return The bit set.
+ */
+ private BitSet bitSet(String[] elements)
+ {
+ BitSet b = new BitSet();
+
+ for (int i = 0; i < elements.length; i++)
+ {
+ Element e = getElement(elements [ i ]);
+
+ if (e == null)
+ e = newElement(elements [ i ]);
+
+ b.set(e.index);
+ }
+
+ return b;
+ }
+
+ /**
+ * Find the element with the given name in the element table.
+ * If not find, create a new element with this name and add to the
+ * table.
+ * @param name the name of the element
+ * @return the found or created element.
+ */
+ private Element newElement(String name)
+ {
+ Element e = elementHash.get(name.toLowerCase());
+
+ if (e == null)
+ {
+ e = new Element();
+ e.name = name;
+ e.index = elements.size();
+ elements.add(e);
+ elementHash.put(e.name.toLowerCase(), e);
+ assignField(e);
+ }
+ return e;
+ }
+
+ /**
+ * Creates and adds to the element table the entity with an
+ * unitialized data section. Used internally.
+ * @param name the name of the entity
+ * @param type the type of the entity, a bitwise combination
+ * of GENERAL, PARAMETER, SYSTEM and PUBLIC.
+ *
+ * @return the created entity
+ */
+ private Entity newEntity(String name, int type)
+ {
+ Entity e = new Entity(name, type, null);
+ entityHash.put(e.name, e);
+ return e;
+ }
+
+ private void unexpected(Exception ex)
+ {
+ throw new Error("This should never happen, report a bug", ex);
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/parser/DTDConstants.java b/libjava/classpath/javax/swing/text/html/parser/DTDConstants.java
new file mode 100644
index 000000000..75e7afb4d
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/parser/DTDConstants.java
@@ -0,0 +1,292 @@
+/* DTDConstants.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html.parser;
+
+/**
+ * <p>This class defines the SGML basic types, used for describing HTML 4.01
+ * at <a href="http://www.w3.org/TR/html4/types.html"
+ * >http://www.w3.org/TR/html4/types.html</a>. Not all constants,
+ * defined here, are actually used in HTML 4.01 SGML specification. Some others
+ * are defined just as part of the required implementation.
+ * </p>
+ * <p>
+ * If you need more information about SGML DTD documents,
+ * the author suggests to read SGML tutorial on
+ * <a href="http://www.w3.org/TR/WD-html40-970708/intro/sgmltut.html"
+ * >http://www.w3.org/TR/WD-html40-970708/intro/sgmltut.html</a>.
+ * We also recommend Goldfarb C.F (1991) <i>The SGML Handbook</i>,
+ * Oxford University Press, 688 p, ISBN: 0198537379.
+ * </p>
+ *
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public interface DTDConstants
+{
+ /* ----- The data types, used in HTML 4.01 SGML definition: ---- */
+
+ /**
+ * The CDATA (Character data) constant, specifes the content model,
+ * consisting of characters only. In SGML for HTML 4.01, the character
+ * entities must be replaced by characters, the line feeds must be
+ * ignored and any number of the subsequent carriage returns or tabs
+ * must be replaced by a single space.
+ */
+ int CDATA = 1;
+
+ /**
+ * The EMPTY constant, means the element with no content.
+ */
+ int EMPTY = 17;
+
+ /**
+ * The ID constant, means that the token is the unique identifier.
+ * This identifier can be referenced by attribute with value of IDREF.
+ * The identifier must begin with letter, followed by any number of
+ * letters, digits, hyphens, underscores, colons and periods.
+ */
+ int ID = 4;
+
+ /**
+ * The IDREF constant, specifies reference to a valid ID within
+ * the document.
+ */
+ int IDREF = 5;
+
+ /**
+ * The IDREFS constant, a space separated list of IDREFs
+ */
+ int IDREFS = 6;
+
+ /**
+ * The NAME constant, means the token that
+ * must begin with letter, followed by any number of
+ * letters, digits, hyphens, underscores, colons and periods.
+ */
+ int NAME = 7;
+
+ /**
+ * The NAMES constant, specifies a space separated of NAMEs.
+ */
+ int NAMES = 8;
+
+ /**
+ * The NMTOKEN constant, specifies the attribute, consisting of
+ * characters that can be either digits or alphabetic characters).
+ */
+ int NMTOKEN = 9;
+
+ /**
+ * The NMTOKENS constant, specifies a list of NMTOKENs.
+ */
+ int NMTOKENS = 10;
+
+ /**
+ * The NOTATION constant, a previously defined data type.
+ */
+ int NOTATION = 11;
+
+ /**
+ * The NUMBER constant (means that the attribute consists of at least
+ * one decimal digit).
+ */
+ int NUMBER = 12;
+
+ /**
+ * The NUMBERS constant, specifies a space separated list of NUMBERs.
+ */
+ int NUMBERS = 13;
+
+ /**
+ * The NUTOKEN constant.
+ */
+ int NUTOKEN = 14;
+
+ /**
+ * The NUTOKENS constant.
+ */
+ int NUTOKENS = 15;
+
+ /* -------
+ The entity scope constants.
+ As these four constants are combined with the bitwise OR,
+ they are defined in the hexadecimal notation.
+ The reason of setting the two bits at once (for PUBLIC and SYSTEM)
+ is probably historical. ----- */
+
+ /**
+ * The PUBLIC constant, specifies the public entity. The PUBLIC entities
+ * are assumed to be known to many systems so that a full declaration
+ * need not be transmitted. For example,
+ * &lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"&gt;
+ */
+ int PUBLIC = 0xA;
+
+ /**
+ * The SYSTEM constant, specifies the system entitiy. The system entities
+ * are assumed to be known but require the clear identifer
+ * (like the file path), where they can be found in the system.
+ * For example, <code>
+ * &lt;DOCTYPE html SYSTEM "/path/to/file.dtd"&gt; </code>.
+ */
+ int SYSTEM = 0x11;
+
+ /**
+ * The PARAMETER constant, specifies that entity is only valid
+ * inside SGML DTD scope.
+ */
+ int PARAMETER = 0x40000;
+
+ /**
+ * The GENERAL constant, specifies theat the entity is valid in the
+ * whole HTML document scope.
+ */
+ int GENERAL = 0x10000;
+
+ /* ---- The constants, defining if the element attribute is required,
+ fixed or implied. ---- */
+
+ /**
+ * The attribute modifier #REQUIRED constant, indicates that the
+ * value must be supplied.
+ */
+ int REQUIRED = 2;
+
+ /**
+ * The attribute modifier #FIXED constant, means that the attribute has
+ * the fixed value that cannot be changed.
+ */
+ int FIXED = 1;
+
+ /**
+ * The attribute modifier #IMPLIED constant,
+ * indicating that for this attribute the user agent must provide
+ * the value itself.
+ */
+ int IMPLIED = 5;
+
+ /**
+ * The attribute modifier #CURRENT constant, specifies the value
+ * that at any point in the document is the last value supplied for
+ * that element. A value is required to be supplied for the first
+ * occurrence of an element
+ */
+ int CURRENT = 3;
+
+ /**
+ * The attribute modifier #CONREF constant, specifies the IDREF value of
+ * the reference to content in another location of the document.
+ * The element with this attribute is empty, the content from
+ * that another location must be used instead.
+ */
+ int CONREF = 4;
+
+ /* ----- Constants, defining if the element
+ start and end tags are required. ---- */
+
+ /**
+ * The STARTTAG, meaning that the element needs a starting tag.
+ */
+ int STARTTAG = 13;
+
+ /**
+ * The ENDTAG constant, meaning that the element needs a closing tag.
+ */
+ int ENDTAG = 14;
+
+ /* ----- Other constants: ----- */
+
+ /**
+ * The ANY constant, specifies
+ * an attribute, consisting from arbitrary characters.
+ */
+ int ANY = 19;
+
+ /**
+ * The DEFAULT constant, specifies the default value.
+ */
+ int DEFAULT = 131072;
+
+ /**
+ * The ENTITIES constant (list of ENTITYes)
+ */
+ int ENTITIES = 3;
+
+ /**
+ * The ENTITY constant, meaning the numeric or symbolic name of some
+ * HTML data.
+ */
+ int ENTITY = 2;
+
+ /**
+ * The MD constant.
+ */
+ int MD = 16;
+
+ /**
+ * The MODEL constant.
+ */
+ int MODEL = 18;
+
+ /**
+ * The MS constant.
+ */
+ int MS = 15;
+
+ /**
+ * The PI (Processing Instruction) constant, specifies a processing
+ * instruction. Processing instructions are used to embed information
+ * intended for specific applications.
+ */
+ int PI = 12;
+
+ /**
+ * The RCDATA constant (Entity References and Character Data), specifies
+ * the content model, consisting of characters AND entities. The
+ * "&lt;" is threated as an ordinary character, but
+ * "<code>&amp;name;</code>" still means the general entity with
+ * the given name.
+ */
+ int RCDATA = 16;
+
+ /**
+ * The SDATA constant. Means that the value contains the entity name
+ * and the replacement value of a character entity reference.
+ */
+ int SDATA = 11;
+}
diff --git a/libjava/classpath/javax/swing/text/html/parser/DocumentParser.java b/libjava/classpath/javax/swing/text/html/parser/DocumentParser.java
new file mode 100644
index 000000000..f717d69cb
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/parser/DocumentParser.java
@@ -0,0 +1,268 @@
+/* DocumentParser.java -- A parser for HTML documents.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html.parser;
+
+import javax.swing.text.html.parser.Parser;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.html.HTMLEditorKit;
+
+/**
+ * <p>A simple error-tolerant HTML parser that uses a DTD document
+ * to access data on the possible tokens, arguments and syntax.</p>
+ * <p> The parser reads an HTML content from a Reader and calls various
+ * notifying methods (which should be overridden in a subclass)
+ * when tags or data are encountered.</p>
+ * <p>Some HTML elements need no opening or closing tags. The
+ * task of this parser is to invoke the tag handling methods also when
+ * the tags are not explicitly specified and must be supposed using
+ * information, stored in the DTD.
+ * For example, parsing the document
+ * <p>&lt;table&gt;&lt;tr&gt;&lt;td&gt;a&lt;td&gt;b&lt;td&gt;c&lt;/tr&gt; <br>
+ * will invoke exactly the handling methods exactly in the same order
+ * (and with the same parameters) as if parsing the document: <br>
+ * <em>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;table&gt;&lt;
+ * tbody&gt;</em>&lt;tr&gt;&lt;td&gt;a<em>&lt;/td&gt;</em>&lt;td&gt;b<em>
+ * &lt;/td&gt;</em>&lt;td&gt;c<em>&lt;/td&gt;&lt;/tr&gt;</em>&lt;
+ * <em>/tbody&gt;&lt;/table&gt;&lt;/body&gt;&lt;/html&gt;</em></p>
+ * (supposed tags are given in italics). The parser also supports
+ * obsolete elements of HTML syntax.<p>
+ * </p>
+ * In this implementation, DocumentParser is directly derived from its
+ * ancestor without changes of functionality.
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class DocumentParser
+ extends Parser
+ implements DTDConstants
+{
+ /**
+ * The enclosed working parser class.
+ */
+ private class gnuParser
+ extends gnu.javax.swing.text.html.parser.support.Parser
+ {
+ private gnuParser(DTD d)
+ {
+ super(d);
+ }
+
+ protected final void handleComment(char[] comment)
+ {
+ parser.handleComment(comment);
+ callBack.handleComment(comment, hTag.where.startPosition);
+ }
+
+ protected final void handleEmptyTag(TagElement tag)
+ throws javax.swing.text.ChangedCharSetException
+ {
+ parser.handleEmptyTag(tag);
+ callBack.handleSimpleTag(tag.getHTMLTag(), getAttributes(),
+ hTag.where.startPosition
+ );
+ }
+
+ protected final void handleEndTag(TagElement tag)
+ {
+ parser.handleEndTag(tag);
+ callBack.handleEndTag(tag.getHTMLTag(), hTag.where.startPosition);
+ }
+
+ protected final void handleError(int line, String message)
+ {
+ parser.handleError(line, message);
+ callBack.handleError(message, hTag.where.startPosition);
+ }
+
+ protected final void handleStartTag(TagElement tag)
+ {
+ parser.handleStartTag(tag);
+ SimpleAttributeSet attributes = gnu.getAttributes();
+
+ if (tag.fictional())
+ attributes.addAttribute(HTMLEditorKit.ParserCallback.IMPLIED,
+ Boolean.TRUE
+ );
+
+ callBack.handleStartTag(tag.getHTMLTag(), attributes,
+ hTag.where.startPosition
+ );
+ }
+
+ protected final void handleText(char[] text)
+ {
+ parser.handleText(text);
+ callBack.handleText(text, hTag.where.startPosition);
+ }
+
+ DTD getDTD()
+ {
+ return dtd;
+ }
+ }
+
+ /**
+ * This field is used to access the identically named
+ * methods of the outer class.
+ * This is package-private to avoid an accessor method.
+ */
+ DocumentParser parser = this;
+
+ /**
+ * The callback.
+ * This is package-private to avoid an accessor method.
+ */
+ HTMLEditorKit.ParserCallback callBack;
+
+ /**
+ * The reference to the working class of HTML parser that is
+ * actually used to parse the document.
+ * This is package-private to avoid an accessor method.
+ */
+ gnuParser gnu;
+
+ /**
+ * Creates a new parser that uses the given DTD to access data on the
+ * possible tokens, arguments and syntax. There is no single - step way
+ * to get a default DTD; you must either refer to the implementation -
+ * specific packages, write your own DTD or obtain the working instance
+ * of parser in other way, for example, by calling
+ * {@link javax.swing.text.html.HTMLEditorKit#getParser()}.
+ *
+ * @param a_dtd a DTD to use.
+ */
+ public DocumentParser(DTD a_dtd)
+ {
+ super(a_dtd);
+ gnu = new gnuParser(a_dtd);
+ }
+
+ /**
+ * Parses the HTML document, calling methods of the provided
+ * callback. This method must be multithread - safe.
+ * @param reader The reader to read the HTML document from
+ * @param aCallback The callback that is notifyed about the presence
+ * of HTML elements in the document.
+ * @param ignoreCharSet If thrue, any charset changes during parsing
+ * are ignored.
+ * @throws java.io.IOException
+ */
+ public void parse(Reader reader, HTMLEditorKit.ParserCallback aCallback,
+ boolean ignoreCharSet
+ )
+ throws IOException
+ {
+ callBack = aCallback;
+ gnu.parse(reader);
+
+ callBack.handleEndOfLineString(gnu.getEndOfLineSequence());
+ try
+ {
+ callBack.flush();
+ }
+ catch (BadLocationException ex)
+ {
+ // Convert this into the supported type of exception.
+ throw new IOException(ex.getMessage());
+ }
+ }
+
+ /**
+ * Handle HTML comment. The default method returns without action.
+ * @param comment the comment being handled
+ */
+ protected void handleComment(char[] comment)
+ {
+ // This default implementation does nothing.
+ }
+
+ /**
+ * Handle the tag with no content, like &lt;br&gt;. The method is
+ * called for the elements that, in accordance with the current DTD,
+ * has an empty content.
+ * @param tag the tag being handled.
+ * @throws javax.swing.text.ChangedCharSetException
+ */
+ protected void handleEmptyTag(TagElement tag)
+ throws javax.swing.text.ChangedCharSetException
+ {
+ // This default implementation does nothing.
+ }
+
+ /**
+ * The method is called when the HTML closing tag ((like &lt;/table&gt;)
+ * is found or if the parser concludes that the one should be present
+ * in the current position.
+ * @param tag The tag being handled
+ */
+ protected void handleEndTag(TagElement tag)
+ {
+ // This default implementation does nothing.
+ }
+
+ /* Handle error that has occured in the given line. */
+ protected void handleError(int line, String message)
+ {
+ // This default implementation does nothing.
+ }
+
+ /**
+ * The method is called when the HTML opening tag ((like &lt;table&gt;)
+ * is found or if the parser concludes that the one should be present
+ * in the current position.
+ * @param tag The tag being handled
+ */
+ protected void handleStartTag(TagElement tag)
+ {
+ // This default implementation does nothing.
+ }
+
+ /**
+ * Handle the text section.
+ * @param text a section text.
+ */
+ protected void handleText(char[] text)
+ {
+ // This default implementation does nothing.
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/parser/Element.java b/libjava/classpath/javax/swing/text/html/parser/Element.java
new file mode 100644
index 000000000..c07c07f54
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/parser/Element.java
@@ -0,0 +1,317 @@
+/* Element.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html.parser;
+
+import gnu.javax.swing.text.html.parser.support.gnuStringIntMapper;
+
+import java.io.Serializable;
+
+import java.util.BitSet;
+
+/**
+ * <p>
+ * Stores the element information, obtained by parsing SGML DTD
+ * tag <code>&lt;!ELEMENT .. &gt;</code>. This class has no public
+ * constructor and can only be instantiated using the
+ * {@link javax.swing.text.html.parser.DTD } methods</p>
+ *
+ * <p>SGML defines elements that represent structures or
+ * behavior. An element typically consists of a start tag, content, and an
+ * end tag. Hence the elements are not tags. The HTML 4.0 definition specifies
+ * that some elements are not required to have the end tags. Also, some
+ * HTML elements (like <code>&lt;hr&gt;</code>) have no content. Element names
+ * are case sensitive.</p>
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public final class Element
+ implements DTDConstants, Serializable
+{
+ /**
+ * Package level mapper between type names and they string values.
+ */
+ static final gnuStringIntMapper mapper =
+ new gnuStringIntMapper()
+ {
+ protected void create()
+ {
+ add("CDATA", DTDConstants.CDATA);
+ add("RCDATA", DTDConstants.RCDATA);
+ add("EMPTY", DTDConstants.EMPTY);
+ add("ANY", DTDConstants.ANY);
+ }
+ };
+
+ /** Use serialVersionUID for interoperability. */
+ private static final long serialVersionUID = -6717939384601675586L;
+
+ /**
+ * The element attributes.
+ */
+ public AttributeList atts;
+
+ /**
+ * Contains refernces to elements that must NOT occur inside this element,
+ * at any level of hierarchy.
+ */
+ public BitSet exclusions;
+
+ /**
+ * Contains refernces to elements that must CAN occur inside this element,
+ * at any level of hierarchy.
+ */
+ public BitSet inclusions;
+
+ /**
+ * The content model, defining elements, entities and DTD text
+ * that may/may not occur inside this element.
+ */
+ public ContentModel content;
+
+ /**
+ * A field to store additional user data for this Element.
+ */
+ public Object data;
+
+ /**
+ * The element name.
+ */
+ public String name;
+
+ /**
+ * True is this element need not to have the closing tag, false
+ * otherwise. The HTML 4.0 definition specifies
+ * that some elements (like <code>&lt;hr&gt;</code>are
+ * not required to have the end tags.
+ */
+ public boolean oEnd;
+
+ /**
+ * True is this element need not to have the starting tag, false
+ * otherwise. The HTML 4.0 definition specifies
+ * that some elements (like <code>&lt;head&gt;</code> or
+ * <code>&lt;body&gt;</code>) are
+ * not required to have the start tags.
+
+ */
+ public boolean oStart;
+
+ /**
+ * This field contains the unique integer identifier of this Element,
+ * used to refer the element (more exactly, the element flag)
+ * in <code>inclusions</code> and <code>exclusions</code> bit set.
+ */
+ public int index;
+
+ /**
+ * The element type, containing value, defined in DTDConstants.
+ * In this implementation, the element type can be
+ * CDATA, RCDATA, EMPTY or ANY.
+ */
+ public int type;
+
+ /**
+ * The default constructor must have package level access in this
+ * class. Use DTD.defineElement(..) to create an element when required.
+ */
+ Element()
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Converts the string representation of the element type
+ * into its unique integer identifier, defined in DTDConstants.
+ * @param a_type A name of the type
+ * @return DTDConstants.CDATA, DTDConstants.RCDATA, DTDConstants.EMPTY,
+ * DTDConstants.ANY or null if the type name is not
+ * "CDATA", "RCDATA", "EMPTY" or "ANY". This function is case sensitive.
+ * @throws NullPointerException if <code>a_type</code> is null.
+ */
+ public static int name2type(String a_type)
+ {
+ return mapper.get(a_type);
+ }
+
+ /**
+ * Get the element attribute by name.
+ * @param attribute the attribute name, case insensitive.
+ * @return the correspoding attribute of this element. The class,
+ * for storing as attribute list, as a single attribute, is used to
+ * store a single attribute in this case.
+ * @throws NullPointerException if the attribute name is null.
+ */
+ public AttributeList getAttribute(String attribute)
+ {
+ AttributeList a = atts;
+
+ while (a != null && !attribute.equalsIgnoreCase(a.name))
+ a = a.next;
+
+ return a;
+ }
+
+ /**
+ * Get the element attribute by its value.
+ * @param a_value the attribute value, case insensitive.
+ * @return the correspoding attribute of this element. The class,
+ * for storing as attribute list, as a single attribute, is used to
+ * store a single attribute in this case. If there are several
+ * attributes with the same value, there is no garranty, which one
+ * is returned.
+ */
+ public AttributeList getAttributeByValue(String a_value)
+ {
+ AttributeList a = atts;
+
+ if (a_value == null)
+ {
+ while (a != null)
+ {
+ if (a.value == null)
+ return a;
+
+ a = a.next;
+ }
+ }
+ else
+ {
+ while (a != null)
+ {
+ if (a.value != null && a_value.equalsIgnoreCase(a.value))
+ return a;
+
+ a = a.next;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Get all attributes of this document as an attribute list.
+ * @return The attribute list.
+ */
+ public AttributeList getAttributes()
+ {
+ return atts;
+ }
+
+ /**
+ * Get the content model, defining elements, entities and DTD text
+ * that may/may not occur inside this element.
+ */
+ public ContentModel getContent()
+ {
+ return content;
+ }
+
+ /**
+ * Returns true for the element with no content.
+ * Empty elements are defined with the SGML DTD keyword "EMPTY".
+ * @return true if content model field (content) method is equal to
+ * null or its method empty() returns true.
+ */
+ public boolean isEmpty()
+ {
+ return content == null || content.empty();
+ }
+
+ /**
+ * Get the unique integer identifier of this Element,
+ * used to refer the element (more exactly, the element flag)
+ * in <code>inclusions</code> and <code>exclusions</code> bit set.
+ * WARNING: This value may not be the same between different
+ * implementations.
+ */
+ public int getIndex()
+ {
+ return index;
+ }
+
+ /**
+ * Get the element name.
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Get the element type.
+ * @return one of the values, defined DTDConstants.
+ * In this implementation, the element type can be
+ * CDATA, RCDATA, EMPTY or ANY.
+ */
+ public int getType()
+ {
+ return type;
+ }
+
+ /**
+ * True is this element need not to have the starting tag, false
+ * otherwise.s element need not to have the closing tag, false
+ * otherwise. The HTML 4.0 definition specifies
+ * that some elements (like <code>&lt;hr&gt;</code>are
+ * not required to have the end tags.
+ */
+ public boolean omitEnd()
+ {
+ return oEnd;
+ }
+
+ /**
+ * True is this element need not to have the closing tag, false
+ * otherwise. The HTML 4.0 definition specifies
+ * that some elements (like <code>&lt;head&gt;</code> or
+ * <code>&lt;body&gt;</code>) are
+ * not required to have the start tags.
+ */
+ public boolean omitStart()
+ {
+ return oStart;
+ }
+
+ /**
+ * Returns the name of this element.
+ */
+ public String toString()
+ {
+ return name;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/parser/Entity.java b/libjava/classpath/javax/swing/text/html/parser/Entity.java
new file mode 100644
index 000000000..d40fb94f3
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/parser/Entity.java
@@ -0,0 +1,183 @@
+/* Entity.java -- Stores information, obtained by parsing SGML DTL
+ * &lt;!ENTITY % .. &gt; tag
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html.parser;
+
+import gnu.javax.swing.text.html.parser.support.gnuStringIntMapper;
+
+/**
+ * <p>Stores information, obtained by parsing SGML DTL
+ * &lt;!ENTITY % .. &gt; tag.</p>
+ * <p>
+ * The entity defines some kind of macro that can be used elsewhere in
+ * the document.
+ * When the macro is referred to by the name in the DTD, it is expanded into
+ * a string
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public final class Entity
+ implements DTDConstants
+{
+ /**
+ * Package level mapper between type names and they string values.
+ */
+ final static gnuStringIntMapper mapper =
+ new gnuStringIntMapper()
+ {
+ protected void create()
+ {
+ add("ANY", DTDConstants.ANY);
+ add("CDATA", DTDConstants.CDATA);
+ add("PUBLIC", DTDConstants.PUBLIC);
+ add("SDATA", DTDConstants.SDATA);
+ add("PI", DTDConstants.PI);
+ add("STARTTAG", DTDConstants.STARTTAG);
+ add("ENDTAG", DTDConstants.ENDTAG);
+ add("MS", DTDConstants.MS);
+ add("MD", DTDConstants.MD);
+ add("SYSTEM", DTDConstants.SYSTEM);
+ }
+ };
+
+ /**
+ * The entity name.
+ */
+ public String name;
+
+ /**
+ * The entity data
+ */
+ public char[] data;
+
+ /**
+ * The entity type.
+ */
+ public int type;
+
+ /**
+ * String representation of the entity data.
+ */
+ private String sdata;
+
+ /**
+ * Create a new entity
+ * @param a_name the entity name
+ * @param a_type the entity type
+ * @param a_data the data replacing the entity reference
+ */
+ public Entity(String a_name, int a_type, char[] a_data)
+ {
+ name = a_name;
+ type = a_type;
+ data = a_data;
+ }
+
+ /**
+ * Converts a given string to the corresponding entity type.
+ * @return a value, defined in DTDConstants (one of
+ * PUBLIC, CDATA, SDATA, PI, STARTTAG, ENDTAG, MS, MD, SYSTEM)
+ * or CDATA if the parameter is not a valid entity type.
+ */
+ public static int name2type(String an_entity)
+ {
+ int r = mapper.get(an_entity);
+ return (r == 0) ? DTDConstants.CDATA : r;
+ }
+
+ /**
+ * Get the entity data.
+ */
+ public char[] getData()
+ {
+ return data;
+ }
+
+ /**
+ * Returns true for general entities. Each general entity can be
+ * referenced as <code>&entity-name;</code>. Such entities are
+ * defined by the SGML DTD tag
+ * <code>&lt;!ENTITY <i>name</i> "<i>value</i>"></code>. The general
+ * entities can be used anywhere in the document.
+ */
+ public boolean isGeneral()
+ {
+ return (type & DTDConstants.GENERAL) != 0;
+ }
+
+ /**
+ * Get the entity name.
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Returns true for parameter entities. Each parameter entity can be
+ * referenced as <code>&entity-name;</code>. Such entities are
+ * defined by the SGML DTD tag
+ * <code>&lt;!ENTITY % <i>name</i> "<i>value</i>"></code>. The parameter
+ * entities can be used only in SGML context.
+ */
+ public boolean isParameter()
+ {
+ return (type & DTDConstants.PARAMETER) != 0;
+ }
+
+ /**
+ * Returns a data as String
+ */
+ public String getString()
+ {
+ if (sdata == null)
+ sdata = new String(data);
+
+ return sdata;
+ }
+
+ /**
+ * Get the entity type.
+ * @return the value of the {@link #type}.
+ */
+ public int getType()
+ {
+ return type;
+ }
+
+}
diff --git a/libjava/classpath/javax/swing/text/html/parser/Parser.java b/libjava/classpath/javax/swing/text/html/parser/Parser.java
new file mode 100644
index 000000000..f3faa2524
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/parser/Parser.java
@@ -0,0 +1,446 @@
+/* Parser.java -- HTML parser
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html.parser;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import javax.swing.text.ChangedCharSetException;
+import javax.swing.text.SimpleAttributeSet;
+
+/*
+ * FOR DEVELOPERS: To avoid regression, please run the package test
+ * textsuite/javax.swing.text.html.parser/AllParserTests after your
+ * modifications.
+ */
+
+/**
+ * <p>A simple error-tolerant HTML parser that uses a DTD document
+ * to access data on the possible tokens, arguments and syntax.</p>
+ * <p> The parser reads an HTML content from a Reader and calls various
+ * notifying methods (which should be overridden in a subclass)
+ * when tags or data are encountered.</p>
+ * <p>Some HTML elements need no opening or closing tags. The
+ * task of this parser is to invoke the tag handling methods also when
+ * the tags are not explicitly specified and must be supposed using
+ * information, stored in the DTD.
+ * For example, parsing the document
+ * <p>&lt;table&gt;&lt;tr&gt;&lt;td&gt;a&lt;td&gt;b&lt;td&gt;c&lt;/tr&gt; <br>
+ * will invoke exactly the handling methods exactly in the same order
+ * (and with the same parameters) as if parsing the document: <br>
+ * <em>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;table&gt;&lt;
+ * tbody&gt;</em>&lt;tr&gt;&lt;td&gt;a<em>&lt;/td&gt;</em>&lt;td&gt;b<em>
+ * &lt;/td&gt;</em>&lt;td&gt;c<em>&lt;/td&gt;&lt;/tr&gt;</em>&lt;
+ * <em>/tbody&gt;&lt;/table&gt;&lt;/body&gt;&lt;/html&gt;</em></p>
+ * (supposed tags are given in italics). The parser also supports
+ * obsolete elements of HTML syntax.<p>
+ * </p>
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class Parser
+ implements DTDConstants
+{
+ /**
+ * The document template description that will be used to parse the documents.
+ */
+ protected DTD dtd;
+
+ /**
+ * The value of this field determines whether or not the Parser will be
+ * strict in enforcing SGML compatibility. The default value is false,
+ * stating that the parser should do everything to parse and get at least
+ * some information even from the incorrectly written HTML input.
+ */
+ protected boolean strict;
+
+ /**
+ * The package level reference to the working HTML parser in this
+ * implementation.
+ */
+ final gnu.javax.swing.text.html.parser.support.Parser gnu;
+
+ /**
+ * Creates a new parser that uses the given DTD to access data on the
+ * possible tokens, arguments and syntax. There is no single - step way
+ * to get a default DTD; you must either refer to the implementation -
+ * specific packages, write your own DTD or obtain the working instance
+ * of parser in other way, for example, by calling
+ * {@link javax.swing.text.html.HTMLEditorKit#getParser() }.
+ * @param a_dtd A DTD to use.
+ */
+ public Parser(DTD a_dtd)
+ {
+ dtd = a_dtd;
+
+ final Parser j = this;
+
+ gnu =
+ new gnu.javax.swing.text.html.parser.support.Parser(dtd)
+ {
+ protected final void handleComment(char[] comment)
+ {
+ j.handleComment(comment);
+ }
+
+ protected final void handleEOFInComment()
+ {
+ j.handleEOFInComment();
+ }
+
+ protected final void handleEmptyTag(TagElement tag)
+ throws javax.swing.text.ChangedCharSetException
+ {
+ j.handleEmptyTag(tag);
+ }
+
+ protected final void handleStartTag(TagElement tag)
+ {
+ j.handleStartTag(tag);
+ }
+
+ protected final void handleEndTag(TagElement tag)
+ {
+ j.handleEndTag(tag);
+ }
+
+ protected final void handleError(int line, String message)
+ {
+ j.handleError(line, message);
+ }
+
+ protected final void handleText(char[] text)
+ {
+ j.handleText(text);
+ }
+
+ protected final void handleTitle(char[] title)
+ {
+ j.handleTitle(title);
+ }
+
+ protected final void markFirstTime(Element element)
+ {
+ j.markFirstTime(element);
+ }
+
+ protected final void startTag(TagElement tag)
+ throws ChangedCharSetException
+ {
+ j.startTag(tag);
+ }
+
+ protected final void endTag(boolean omitted)
+ {
+ j.endTag(omitted);
+ }
+
+ protected TagElement makeTag(Element element)
+ {
+ return j.makeTag(element);
+ }
+
+ protected TagElement makeTag(Element element, boolean isSupposed)
+ {
+ return j.makeTag(element, isSupposed);
+ }
+ };
+ }
+
+ /**
+ * Parse the HTML text, calling various methods in response to the
+ * occurence of the corresponding HTML constructions.
+ * @param reader The reader to read the source HTML from.
+ * @throws IOException If the reader throws one.
+ */
+ public synchronized void parse(Reader reader)
+ throws IOException
+ {
+ gnu.parse(reader);
+ }
+
+ /**
+ * Parses DTD markup declaration. Currently returns without action.
+ * @return null.
+ * @throws java.io.IOException
+ */
+ public String parseDTDMarkup()
+ throws IOException
+ {
+ return gnu.parseDTDMarkup();
+ }
+
+ /**
+ * Parse DTD document declarations. Currently only parses the document
+ * type declaration markup.
+ * @param strBuff
+ * @return true if this is a valid DTD markup declaration.
+ * @throws IOException
+ */
+ protected boolean parseMarkupDeclarations(StringBuffer strBuff)
+ throws IOException
+ {
+ return gnu.parseMarkupDeclarations(strBuff);
+ }
+
+ /**
+ * Get the attributes of the current tag.
+ * @return The attribute set, representing the attributes of the current tag.
+ */
+ protected SimpleAttributeSet getAttributes()
+ {
+ return gnu.getAttributes();
+ }
+
+ /**
+ * Get the number of the document line being parsed.
+ * @return The current line.
+ */
+ protected int getCurrentLine()
+ {
+ return gnu.hTag.where.beginLine;
+ }
+
+ /**
+ * Get the current position in the document being parsed.
+ * @return The current position.
+ */
+ protected int getCurrentPos()
+ {
+ return gnu.hTag.where.startPosition;
+ }
+
+ /**
+ * The method is called when the HTML end (closing) tag is found or if
+ * the parser concludes that the one should be present in the
+ * current position. The method is called immediatly
+ * before calling the handleEndTag().
+ * @param omitted True if the tag is no actually present in the document,
+ * but is supposed by the parser (like &lt;/html&gt; at the end of the
+ * document).
+ */
+ protected void endTag(boolean omitted)
+ {
+ // This default implementation does nothing.
+ }
+
+ /**
+ * Invokes the error handler. The default method in this implementation
+ * finally delegates the call to handleError, also providing the number of the
+ * current line.
+ */
+ protected void error(String msg)
+ {
+ gnu.error(msg);
+ }
+
+ /**
+ * Invokes the error handler. The default method in this implementation
+ * finally delegates the call to error (msg+": '"+invalid+"'").
+ */
+ protected void error(String msg, String invalid)
+ {
+ gnu.error(msg, invalid);
+ }
+
+ /**
+ * Invokes the error handler. The default method in this implementation
+ * finally delegates the call to error (parm1+" "+ parm2+" "+ parm3).
+ */
+ protected void error(String parm1, String parm2, String parm3)
+ {
+ gnu.error(parm1, parm2, parm3);
+ }
+
+ /**
+ * Invokes the error handler. The default method in this implementation
+ * finally delegates the call to error
+ * (parm1+" "+ parm2+" "+ parm3+" "+ parm4).
+ */
+ protected void error(String parm1, String parm2, String parm3, String parm4)
+ {
+ gnu.error(parm1, parm2, parm3, parm4);
+ }
+
+ /**
+ * In this implementation, this is never called and returns without action.
+ */
+ protected void flushAttributes()
+ {
+ gnu.flushAttributes();
+ }
+
+ /**
+ * Handle HTML comment. The default method returns without action.
+ * @param comment The comment being handled
+ */
+ protected void handleComment(char[] comment)
+ {
+ // This default implementation does nothing.
+ }
+
+ /**
+ * This is additionally called in when the HTML content terminates
+ * without closing the HTML comment. This can only happen if the
+ * HTML document contains errors (for example, the closing --;gt is
+ * missing. The default method calls the error handler.
+ */
+ protected void handleEOFInComment()
+ {
+ gnu.error("Unclosed comment");
+ }
+
+ /**
+ * Handle the tag with no content, like &lt;br&gt;. The method is
+ * called for the elements that, in accordance with the current DTD,
+ * has an empty content.
+ * @param tag The tag being handled.
+ * @throws javax.swing.text.ChangedCharSetException
+ */
+ protected void handleEmptyTag(TagElement tag)
+ throws ChangedCharSetException
+ {
+ // This default implementation does nothing.
+ }
+
+ /**
+ * The method is called when the HTML closing tag ((like &lt;/table&gt;)
+ * is found or if the parser concludes that the one should be present
+ * in the current position.
+ * @param tag The tag being handled
+ */
+ protected void handleEndTag(TagElement tag)
+ {
+ // This default implementation does nothing.
+ }
+
+ /* Handle error that has occured in the given line. */
+ protected void handleError(int line, String message)
+ {
+ // This default implementation does nothing.
+ }
+
+ /**
+ * The method is called when the HTML opening tag ((like &lt;table&gt;)
+ * is found or if the parser concludes that the one should be present
+ * in the current position.
+ * @param tag The tag being handled
+ */
+ protected void handleStartTag(TagElement tag)
+ {
+ // This default implementation does nothing.
+ }
+
+ /**
+ * Handle the text section.
+ * <p> For non-preformatted section, the parser replaces
+ * \t, \r and \n by spaces and then multiple spaces
+ * by a single space. Additionaly, all whitespace around
+ * tags is discarded.
+ * </p>
+ * <p> For pre-formatted text (inside TEXAREA and PRE), the parser preserves
+ * all tabs and spaces, but removes <b>one</b> bounding \r, \n or \r\n,
+ * if it is present. Additionally, it replaces each occurence of \r or \r\n
+ * by a single \n.</p>
+ *
+ * @param text A section text.
+ */
+ protected void handleText(char[] text)
+ {
+ // This default implementation does nothing.
+ }
+
+ /**
+ * Handle HTML &lt;title&gt; tag. This method is invoked when
+ * both title starting and closing tags are already behind.
+ * The passed argument contains the concatenation of all
+ * title text sections.
+ * @param title The title text.
+ */
+ protected void handleTitle(char[] title)
+ {
+ // This default implementation does nothing.
+ }
+
+ /**
+ * Constructs the tag from the given element. In this implementation,
+ * this is defined, but never called.
+ * @param element the base element of the tag.
+ * @return the tag
+ */
+ protected TagElement makeTag(Element element)
+ {
+ return makeTag(element, false);
+ }
+
+ /**
+ * Constructs the tag from the given element.
+ * @param element the tag base {@link javax.swing.text.html.parser.Element}
+ * @param isSupposed true if the tag is not actually present in the
+ * html input, but the parser supposes that it should to occur in
+ * the current location.
+ * @return the tag
+ */
+ protected TagElement makeTag(Element element, boolean isSupposed)
+ {
+ return new TagElement(element, isSupposed);
+ }
+
+ /**
+ * This is called when the tag, representing the given element,
+ * occurs first time in the document.
+ * @param element
+ */
+ protected void markFirstTime(Element element)
+ {
+ // This default implementation does nothing.
+ }
+
+ /**
+ * The method is called when the HTML opening tag ((like &lt;table&gt;)
+ * is found or if the parser concludes that the one should be present
+ * in the current position. The method is called immediately before
+ * calling the handleStartTag.
+ * @param tag The tag
+ */
+ protected void startTag(TagElement tag)
+ throws ChangedCharSetException
+ {
+ // This default implementation does nothing.
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java b/libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java
new file mode 100644
index 000000000..cdd339b8f
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java
@@ -0,0 +1,207 @@
+/* ParserDelegator.java -- Delegator for ParserDocument.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html.parser;
+
+import gnu.javax.swing.text.html.parser.HTML_401F;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Serializable;
+
+import javax.swing.text.BadLocationException;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.html.HTMLEditorKit;
+import javax.swing.text.html.HTMLEditorKit.ParserCallback;
+
+/**
+ * This class instantiates and starts the working instance of
+ * html parser, being responsible for providing the default DTD.
+ *
+ * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
+ */
+public class ParserDelegator
+ extends javax.swing.text.html.HTMLEditorKit.Parser
+ implements Serializable
+{
+ private class gnuParser
+ extends gnu.javax.swing.text.html.parser.support.Parser
+ {
+ private static final long serialVersionUID = 1;
+
+ private gnuParser(DTD d)
+ {
+ super(d);
+ }
+
+ protected final void handleComment(char[] comment)
+ {
+ callBack.handleComment(comment, hTag.where.startPosition);
+ }
+
+ protected final void handleEmptyTag(TagElement tag)
+ throws javax.swing.text.ChangedCharSetException
+ {
+ callBack.handleSimpleTag(tag.getHTMLTag(), getAttributes(),
+ hTag.where.startPosition
+ );
+ }
+
+ protected final void handleEndTag(TagElement tag)
+ {
+ callBack.handleEndTag(tag.getHTMLTag(), hTag.where.startPosition);
+ }
+
+ protected final void handleError(int line, String message)
+ {
+ callBack.handleError(message, hTag.where.startPosition);
+ }
+
+ protected final void handleStartTag(TagElement tag)
+ {
+ SimpleAttributeSet attributes = gnu.getAttributes();
+
+ if (tag.fictional())
+ attributes.addAttribute(ParserCallback.IMPLIED, Boolean.TRUE);
+
+ callBack.handleStartTag(tag.getHTMLTag(), attributes,
+ hTag.where.startPosition
+ );
+ }
+
+ protected final void handleText(char[] text)
+ {
+ callBack.handleText(text, hTag.where.startPosition);
+ }
+
+ DTD getDTD()
+ {
+ // Accessing the inherited gnu.javax.swing.text.html.parser.support.Parser
+ // field. super. is a workaround, required to support JDK1.3's javac.
+ return super.dtd;
+ }
+ }
+
+ /**
+ * Use serialVersionUID for interoperability.
+ */
+ private static final long serialVersionUID = -1276686502624777206L;
+
+ private static DTD dtd = HTML_401F.getInstance();
+
+ /**
+ * The callback.
+ * This is package-private to avoid an accessor method.
+ */
+ HTMLEditorKit.ParserCallback callBack;
+
+ /**
+ * The reference to the working class of HTML parser that is
+ * actually used to parse the document.
+ * This is package-private to avoid an accessor method.
+ */
+ gnuParser gnu;
+
+ /**
+ * Parses the HTML document, calling methods of the provided
+ * callback. This method must be multithread - safe.
+ * @param reader The reader to read the HTML document from
+ * @param a_callback The callback that is notifyed about the presence
+ * of HTML elements in the document.
+ * @param ignoreCharSet If thrue, any charset changes during parsing
+ * are ignored.
+ * @throws java.io.IOException
+ */
+ public void parse(Reader reader, HTMLEditorKit.ParserCallback a_callback,
+ boolean ignoreCharSet
+ )
+ throws IOException
+ {
+ callBack = a_callback;
+
+ if (gnu == null || !dtd.equals(gnu.getDTD()))
+ {
+ gnu = new gnuParser(dtd);
+ }
+
+ gnu.parse(reader);
+
+ callBack.handleEndOfLineString(gnu.getEndOfLineSequence());
+ try
+ {
+ callBack.flush();
+ }
+ catch (BadLocationException ex)
+ {
+ // Convert this into the supported type of exception.
+ throw new IOException(ex.getMessage());
+ }
+ }
+
+ /**
+ * Calling this method instructs that, if not specified directly,
+ * the documents will be parsed using the default
+ * DTD of the implementation.
+ */
+ protected static void setDefaultDTD()
+ {
+ dtd = HTML_401F.getInstance();
+ }
+
+ /**
+ * Registers the user - written DTD under the given name, also
+ * making it default for the subsequent parsings. This has effect on
+ * all subsequent calls to the parse(...) . If you need to specify
+ * your DTD locally, simply {@link javax.swing.text.html.parser.Parser}
+ * instead.
+ * @param a_dtd The DTD that will be used to parse documents by this class.
+ * @param name The name of this DTD.
+ * @return No standard is specified on which instance of DTD must be
+ * returned by this method, and it is recommended to leave the returned
+ * value without consideration. This implementation returns the DTD
+ * that was previously set as the default DTD, or the implementations
+ * default DTD if none was set.
+ */
+ protected static DTD createDTD(DTD a_dtd, String name)
+ {
+ DTD.putDTDHash(name, a_dtd);
+
+ DTD dtd_prev = dtd;
+ dtd = a_dtd;
+ return dtd_prev;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/parser/TagElement.java b/libjava/classpath/javax/swing/text/html/parser/TagElement.java
new file mode 100644
index 000000000..4558b15eb
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/parser/TagElement.java
@@ -0,0 +1,142 @@
+/* TagElement.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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 javax.swing.text.html.parser;
+
+import javax.swing.text.html.HTML;
+
+/**
+ * The SGML element, defining a single html tag.
+ * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+ */
+public class TagElement
+{
+ /**
+ * The Element the tag was constructed from.
+ */
+ private final Element element;
+
+ /**
+ * The coresponding HTML tag, assigned once in constructor.
+ */
+ private final HTML.Tag tag;
+
+ /**
+ * The 'fictional' flag.
+ */
+ private final boolean fictional;
+
+ /**
+ * Creates the html tag element from the defintion, stored in the
+ * given element. Sets the flag 'fictional' to false.
+ * @param an_element
+ */
+ public TagElement(Element an_element)
+ {
+ this(an_element, false);
+ }
+
+ /**
+ * Creates the html tag element from the defintion, stored in the
+ * given element, setting the flag 'fictional' to the given value.
+ */
+ public TagElement(Element an_element, boolean is_fictional)
+ {
+ element = an_element;
+ fictional = is_fictional;
+
+ HTML.Tag t = HTML.getTag(element.getName());
+
+ if (t != null)
+ tag = t;
+ else
+ tag = new HTML.UnknownTag(element.getName());
+ }
+
+ /**
+ * Get the element from that the tag was constructed.
+ */
+ public Element getElement()
+ {
+ return element;
+ }
+
+ /**
+ * Get the corresponding HTML tag. This is either one of the
+ * pre-defined HTML tags or the instance of the UnknownTag with the
+ * element name.
+ */
+ public HTML.Tag getHTMLTag()
+ {
+ return tag;
+ }
+
+ /**
+ * Calls isPreformatted() for the corresponding html tag and returns
+ * the obtained value.
+ */
+ public boolean isPreformatted()
+ {
+ return tag.isPreformatted();
+ }
+
+ /**
+ * Calls breaksFlow() for the corresponding html tag and returns
+ * the obtained value.
+ */
+ public boolean breaksFlow()
+ {
+ return tag.breaksFlow();
+ }
+
+ /**
+ * Get the value of the flag 'fictional'.
+ */
+ public boolean fictional()
+ {
+ return fictional;
+ }
+
+ /**
+ * Returns string representation of this object.
+ */
+ public String toString()
+ {
+ return getElement() + (fictional ? "?" : "");
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/parser/package.html b/libjava/classpath/javax/swing/text/html/parser/package.html
new file mode 100644
index 000000000..5d5157fb2
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/parser/package.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in javax.swing.text.html package.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+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. -->
+
+<html>
+<head><title>GNU Classpath - javax.swing.text.html.parser</title></head>
+
+<body>
+<p> Provides the DTD driven for web browsers,
+ web robots, web page content analysers, web editors and
+ other applications applications working with Hypertext
+ Markup Language (HTML).
+</p>
+
+</body>
+</html>