feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
3058
jdkSrc/jdk8/javax/swing/text/html/AccessibleHTML.java
Normal file
3058
jdkSrc/jdk8/javax/swing/text/html/AccessibleHTML.java
Normal file
File diff suppressed because it is too large
Load Diff
57
jdkSrc/jdk8/javax/swing/text/html/BRView.java
Normal file
57
jdkSrc/jdk8/javax/swing/text/html/BRView.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import javax.swing.text.*;
|
||||
|
||||
/**
|
||||
* Processes the <BR> tag. In other words, forces a line break.
|
||||
*
|
||||
* @author Sunita Mani
|
||||
*/
|
||||
class BRView extends InlineView {
|
||||
|
||||
/**
|
||||
* Creates a new view that represents a <BR> element.
|
||||
*
|
||||
* @param elem the element to create a view for
|
||||
*/
|
||||
public BRView(Element elem) {
|
||||
super(elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces a line break.
|
||||
*
|
||||
* @return View.ForcedBreakWeight
|
||||
*/
|
||||
public int getBreakWeight(int axis, float pos, float len) {
|
||||
if (axis == X_AXIS) {
|
||||
return ForcedBreakWeight;
|
||||
} else {
|
||||
return super.getBreakWeight(axis, pos, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
443
jdkSrc/jdk8/javax/swing/text/html/BlockView.java
Normal file
443
jdkSrc/jdk8/javax/swing/text/html/BlockView.java
Normal file
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.awt.*;
|
||||
import javax.swing.SizeRequirements;
|
||||
import javax.swing.border.*;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.text.*;
|
||||
|
||||
/**
|
||||
* A view implementation to display a block (as a box)
|
||||
* with CSS specifications.
|
||||
*
|
||||
* @author Timothy Prinzing
|
||||
*/
|
||||
public class BlockView extends BoxView {
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the parent view for this view. This is
|
||||
* guaranteed to be called before any other methods if the
|
||||
* parent view is functioning properly.
|
||||
* <p>
|
||||
* This is implemented
|
||||
* to forward to the superclass as well as call the
|
||||
* {@link #setPropertiesFromAttributes()}
|
||||
* method to set the paragraph properties from the css
|
||||
* attributes. The call is made at this time to ensure
|
||||
* the ability to resolve upward through the parents
|
||||
* view attributes.
|
||||
*
|
||||
* @param parent the new parent, or null if the view is
|
||||
* being removed from a parent it was previously added
|
||||
* to
|
||||
*/
|
||||
public void setParent(View parent) {
|
||||
super.setParent(parent);
|
||||
if (parent != null) {
|
||||
setPropertiesFromAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the requirements of the block along the major
|
||||
* axis (i.e. the axis along with it tiles). This is implemented
|
||||
* to provide the superclass behavior and then adjust it if the
|
||||
* CSS width or height attribute is specified and applicable to
|
||||
* the axis.
|
||||
*/
|
||||
protected SizeRequirements calculateMajorAxisRequirements(int axis, SizeRequirements r) {
|
||||
if (r == null) {
|
||||
r = new SizeRequirements();
|
||||
}
|
||||
if (! spanSetFromAttributes(axis, r, cssWidth, cssHeight)) {
|
||||
r = super.calculateMajorAxisRequirements(axis, r);
|
||||
}
|
||||
else {
|
||||
// Offset by the margins so that pref/min/max return the
|
||||
// right value.
|
||||
SizeRequirements parentR = 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, parentR);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the requirements of the block along the minor
|
||||
* axis (i.e. the axis orthogonal to the axis along with it tiles).
|
||||
* This is implemented
|
||||
* to provide the superclass behavior and then adjust it if the
|
||||
* CSS width or height attribute is specified and applicable to
|
||||
* the axis.
|
||||
*/
|
||||
protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) {
|
||||
if (r == null) {
|
||||
r = new SizeRequirements();
|
||||
}
|
||||
|
||||
if (! spanSetFromAttributes(axis, r, cssWidth, cssHeight)) {
|
||||
|
||||
/*
|
||||
* The requirements were not directly specified by attributes, so
|
||||
* compute the aggregate of the requirements of the children. The
|
||||
* children that have a percentage value specified will be treated
|
||||
* as completely stretchable since that child is not limited in any
|
||||
* way.
|
||||
*/
|
||||
/*
|
||||
int min = 0;
|
||||
long pref = 0;
|
||||
int max = 0;
|
||||
int n = getViewCount();
|
||||
for (int i = 0; i < n; i++) {
|
||||
View v = getView(i);
|
||||
min = Math.max((int) v.getMinimumSpan(axis), min);
|
||||
pref = Math.max((int) v.getPreferredSpan(axis), pref);
|
||||
if (
|
||||
max = Math.max((int) v.getMaximumSpan(axis), max);
|
||||
|
||||
}
|
||||
r.preferred = (int) pref;
|
||||
r.minimum = min;
|
||||
r.maximum = max;
|
||||
*/
|
||||
r = super.calculateMinorAxisRequirements(axis, r);
|
||||
}
|
||||
else {
|
||||
// Offset by the margins so that pref/min/max return the
|
||||
// right value.
|
||||
SizeRequirements parentR = 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, parentR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the alignment based upon the CSS properties if it is
|
||||
* specified. For X_AXIS this would be text-align, for
|
||||
* Y_AXIS this would be vertical-align.
|
||||
*/
|
||||
if (axis == X_AXIS) {
|
||||
Object o = getAttributes().getAttribute(CSS.Attribute.TEXT_ALIGN);
|
||||
if (o != null) {
|
||||
String align = o.toString();
|
||||
if (align.equals("center")) {
|
||||
r.alignment = 0.5f;
|
||||
} else if (align.equals("right")) {
|
||||
r.alignment = 1.0f;
|
||||
} else {
|
||||
r.alignment = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Y_AXIS TBD
|
||||
return r;
|
||||
}
|
||||
|
||||
boolean isPercentage(int axis, AttributeSet a) {
|
||||
if (axis == X_AXIS) {
|
||||
if (cssWidth != null) {
|
||||
return cssWidth.isPercentage();
|
||||
}
|
||||
} else {
|
||||
if (cssHeight != null) {
|
||||
return cssHeight.isPercentage();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the given requirements to the CSS width or height if
|
||||
* it is specified along the applicable axis. Return true if the
|
||||
* size is exactly specified, false if the span is not specified
|
||||
* in an attribute or the size specified is a percentage.
|
||||
*/
|
||||
static boolean spanSetFromAttributes(int axis, SizeRequirements r,
|
||||
CSS.LengthValue cssWidth,
|
||||
CSS.LengthValue cssHeight) {
|
||||
if (axis == X_AXIS) {
|
||||
if ((cssWidth != null) && (! cssWidth.isPercentage())) {
|
||||
r.minimum = r.preferred = r.maximum = (int) cssWidth.getValue();
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if ((cssHeight != null) && (! cssHeight.isPercentage())) {
|
||||
r.minimum = r.preferred = r.maximum = (int) cssHeight.getValue();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs layout for the minor axis of the box (i.e. the
|
||||
* axis orthogonal to the axis that it represents). The results
|
||||
* of the layout (the offset and span for each children) are
|
||||
* placed in the given arrays which represent the allocations to
|
||||
* the children along the minor axis.
|
||||
*
|
||||
* @param targetSpan the total span given to the view, which
|
||||
* would be used to layout the children.
|
||||
* @param axis the axis being layed out
|
||||
* @param offsets the offsets from the origin of the view for
|
||||
* each of the child views; this is a return value and is
|
||||
* filled in by the implementation of this method
|
||||
* @param spans the span of each child view; this is a return
|
||||
* value and is filled in by the implementation of this method
|
||||
*/
|
||||
protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
|
||||
int n = getViewCount();
|
||||
Object key = (axis == X_AXIS) ? CSS.Attribute.WIDTH : CSS.Attribute.HEIGHT;
|
||||
for (int i = 0; i < n; i++) {
|
||||
View v = getView(i);
|
||||
int min = (int) v.getMinimumSpan(axis);
|
||||
int max;
|
||||
|
||||
// check for percentage span
|
||||
AttributeSet a = v.getAttributes();
|
||||
CSS.LengthValue lv = (CSS.LengthValue) a.getAttribute(key);
|
||||
if ((lv != null) && lv.isPercentage()) {
|
||||
// bound the span to the percentage specified
|
||||
min = Math.max((int) lv.getValue(targetSpan), min);
|
||||
max = min;
|
||||
} else {
|
||||
max = (int)v.getMaximumSpan(axis);
|
||||
}
|
||||
|
||||
// assign the offset and span for the child
|
||||
if (max < targetSpan) {
|
||||
// can't make the child this wide, align it
|
||||
float align = v.getAlignment(axis);
|
||||
offsets[i] = (int) ((targetSpan - max) * align);
|
||||
spans[i] = max;
|
||||
} else {
|
||||
// make it the target width, or as small as it can get.
|
||||
offsets[i] = 0;
|
||||
spans[i] = Math.max(min, targetSpan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders using the given rendering surface and area on that
|
||||
* surface. This is implemented to delegate to the css box
|
||||
* painter to paint the border and background prior to the
|
||||
* interior.
|
||||
*
|
||||
* @param g the rendering surface to use
|
||||
* @param allocation the allocated region to render into
|
||||
* @see View#paint
|
||||
*/
|
||||
public void paint(Graphics g, Shape allocation) {
|
||||
Rectangle a = (Rectangle) allocation;
|
||||
painter.paint(g, a.x, a.y, a.width, a.height, this);
|
||||
super.paint(g, a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the attributes to use when rendering. This is
|
||||
* implemented to multiplex the attributes specified in the
|
||||
* model with a StyleSheet.
|
||||
*/
|
||||
public AttributeSet getAttributes() {
|
||||
if (attr == null) {
|
||||
StyleSheet sheet = getStyleSheet();
|
||||
attr = sheet.getViewAttributes(this);
|
||||
}
|
||||
return attr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the resize weight.
|
||||
*
|
||||
* @param axis may be either X_AXIS or Y_AXIS
|
||||
* @return the weight
|
||||
* @exception IllegalArgumentException for an invalid axis
|
||||
*/
|
||||
public int getResizeWeight(int axis) {
|
||||
switch (axis) {
|
||||
case View.X_AXIS:
|
||||
return 1;
|
||||
case View.Y_AXIS:
|
||||
return 0;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid axis: " + axis);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the alignment.
|
||||
*
|
||||
* @param axis may be either X_AXIS or Y_AXIS
|
||||
* @return the alignment
|
||||
*/
|
||||
public float getAlignment(int axis) {
|
||||
switch (axis) {
|
||||
case View.X_AXIS:
|
||||
return 0;
|
||||
case View.Y_AXIS:
|
||||
if (getViewCount() == 0) {
|
||||
return 0;
|
||||
}
|
||||
float span = getPreferredSpan(View.Y_AXIS);
|
||||
View v = getView(0);
|
||||
float above = v.getPreferredSpan(View.Y_AXIS);
|
||||
float a = (((int)span) != 0) ? (above * v.getAlignment(View.Y_AXIS)) / span: 0;
|
||||
return a;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid axis: " + axis);
|
||||
}
|
||||
}
|
||||
|
||||
public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
|
||||
super.changedUpdate(changes, a, f);
|
||||
int pos = changes.getOffset();
|
||||
if (pos <= getStartOffset() && (pos + changes.getLength()) >=
|
||||
getEndOffset()) {
|
||||
setPropertiesFromAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the preferred span for this view along an
|
||||
* axis.
|
||||
*
|
||||
* @param axis may be either <code>View.X_AXIS</code>
|
||||
* or <code>View.Y_AXIS</code>
|
||||
* @return the span the view would like to be rendered into >= 0;
|
||||
* typically the view is told to render into the span
|
||||
* that is returned, although there is no guarantee;
|
||||
* the parent may choose to resize or break the view
|
||||
* @exception IllegalArgumentException for an invalid axis type
|
||||
*/
|
||||
public float getPreferredSpan(int axis) {
|
||||
return super.getPreferredSpan(axis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the minimum span for this view along an
|
||||
* axis.
|
||||
*
|
||||
* @param axis may be either <code>View.X_AXIS</code>
|
||||
* or <code>View.Y_AXIS</code>
|
||||
* @return the span the view would like to be rendered into >= 0;
|
||||
* typically the view is told to render into the span
|
||||
* that is returned, although there is no guarantee;
|
||||
* the parent may choose to resize or break the view
|
||||
* @exception IllegalArgumentException for an invalid axis type
|
||||
*/
|
||||
public float getMinimumSpan(int axis) {
|
||||
return super.getMinimumSpan(axis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the maximum span for this view along an
|
||||
* axis.
|
||||
*
|
||||
* @param axis may be either <code>View.X_AXIS</code>
|
||||
* or <code>View.Y_AXIS</code>
|
||||
* @return the span the view would like to be rendered into >= 0;
|
||||
* typically the view is told to render into the span
|
||||
* that is returned, although there is no guarantee;
|
||||
* the parent may choose to resize or break the view
|
||||
* @exception IllegalArgumentException for an invalid axis type
|
||||
*/
|
||||
public float getMaximumSpan(int axis) {
|
||||
return super.getMaximumSpan(axis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update any cached values that come from attributes.
|
||||
*/
|
||||
protected void setPropertiesFromAttributes() {
|
||||
|
||||
// update attributes
|
||||
StyleSheet sheet = getStyleSheet();
|
||||
attr = sheet.getViewAttributes(this);
|
||||
|
||||
// Reset the painter
|
||||
painter = sheet.getBoxPainter(attr);
|
||||
if (attr != null) {
|
||||
setInsets((short) painter.getInset(TOP, this),
|
||||
(short) painter.getInset(LEFT, this),
|
||||
(short) painter.getInset(BOTTOM, this),
|
||||
(short) painter.getInset(RIGHT, this));
|
||||
}
|
||||
|
||||
// Get the width/height
|
||||
cssWidth = (CSS.LengthValue) attr.getAttribute(CSS.Attribute.WIDTH);
|
||||
cssHeight = (CSS.LengthValue) attr.getAttribute(CSS.Attribute.HEIGHT);
|
||||
}
|
||||
|
||||
protected StyleSheet getStyleSheet() {
|
||||
HTMLDocument doc = (HTMLDocument) getDocument();
|
||||
return doc.getStyleSheet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constrains <code>want</code> to fit in the minimum size specified
|
||||
* by <code>min</code>.
|
||||
*/
|
||||
private void constrainSize(int axis, SizeRequirements want,
|
||||
SizeRequirements min) {
|
||||
if (min.minimum > want.minimum) {
|
||||
want.minimum = want.preferred = min.minimum;
|
||||
want.maximum = Math.max(want.maximum, min.maximum);
|
||||
}
|
||||
}
|
||||
|
||||
private AttributeSet attr;
|
||||
private StyleSheet.BoxPainter painter;
|
||||
|
||||
private CSS.LengthValue cssWidth;
|
||||
private CSS.LengthValue cssHeight;
|
||||
|
||||
}
|
||||
3404
jdkSrc/jdk8/javax/swing/text/html/CSS.java
Normal file
3404
jdkSrc/jdk8/javax/swing/text/html/CSS.java
Normal file
File diff suppressed because it is too large
Load Diff
436
jdkSrc/jdk8/javax/swing/text/html/CSSBorder.java
Normal file
436
jdkSrc/jdk8/javax/swing/text/html/CSSBorder.java
Normal file
@@ -0,0 +1,436 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Polygon;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.swing.border.AbstractBorder;
|
||||
import javax.swing.text.AttributeSet;
|
||||
import javax.swing.text.View;
|
||||
import javax.swing.text.html.CSS.Attribute;
|
||||
import javax.swing.text.html.CSS.BorderStyle;
|
||||
import javax.swing.text.html.CSS.BorderWidthValue;
|
||||
import javax.swing.text.html.CSS.ColorValue;
|
||||
import javax.swing.text.html.CSS.CssValue;
|
||||
import javax.swing.text.html.CSS.LengthValue;
|
||||
import javax.swing.text.html.CSS.Value;
|
||||
|
||||
/**
|
||||
* CSS-style borders for HTML elements.
|
||||
*
|
||||
* @author Sergey Groznyh
|
||||
*/
|
||||
class CSSBorder extends AbstractBorder {
|
||||
|
||||
/** Indices for the attribute groups. */
|
||||
final static int COLOR = 0, STYLE = 1, WIDTH = 2;
|
||||
|
||||
/** Indices for the box sides within the attribute group. */
|
||||
final static int TOP = 0, RIGHT = 1, BOTTOM = 2, LEFT = 3;
|
||||
|
||||
/** The attribute groups. */
|
||||
final static Attribute[][] ATTRIBUTES = {
|
||||
{ Attribute.BORDER_TOP_COLOR, Attribute.BORDER_RIGHT_COLOR,
|
||||
Attribute.BORDER_BOTTOM_COLOR, Attribute.BORDER_LEFT_COLOR, },
|
||||
{ Attribute.BORDER_TOP_STYLE, Attribute.BORDER_RIGHT_STYLE,
|
||||
Attribute.BORDER_BOTTOM_STYLE, Attribute.BORDER_LEFT_STYLE, },
|
||||
{ Attribute.BORDER_TOP_WIDTH, Attribute.BORDER_RIGHT_WIDTH,
|
||||
Attribute.BORDER_BOTTOM_WIDTH, Attribute.BORDER_LEFT_WIDTH, },
|
||||
};
|
||||
|
||||
/** Parsers for the border properties. */
|
||||
final static CssValue PARSERS[] = {
|
||||
new ColorValue(), new BorderStyle(), new BorderWidthValue(null, 0),
|
||||
};
|
||||
|
||||
/** Default values for the border properties. */
|
||||
final static Object[] DEFAULTS = {
|
||||
Attribute.BORDER_COLOR, // marker: value will be computed on request
|
||||
PARSERS[1].parseCssValue(Attribute.BORDER_STYLE.getDefaultValue()),
|
||||
PARSERS[2].parseCssValue(Attribute.BORDER_WIDTH.getDefaultValue()),
|
||||
};
|
||||
|
||||
/** Attribute set containing border properties. */
|
||||
final AttributeSet attrs;
|
||||
|
||||
/**
|
||||
* Initialize the attribute set.
|
||||
*/
|
||||
CSSBorder(AttributeSet attrs) {
|
||||
this.attrs = attrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the border color for the given side.
|
||||
*/
|
||||
private Color getBorderColor(int side) {
|
||||
Object o = attrs.getAttribute(ATTRIBUTES[COLOR][side]);
|
||||
ColorValue cv;
|
||||
if (o instanceof ColorValue) {
|
||||
cv = (ColorValue) o;
|
||||
} else {
|
||||
// Marker for the default value. Use 'color' property value as the
|
||||
// computed value of the 'border-color' property (CSS2 8.5.2)
|
||||
cv = (ColorValue) attrs.getAttribute(Attribute.COLOR);
|
||||
if (cv == null) {
|
||||
cv = (ColorValue) PARSERS[COLOR].parseCssValue(
|
||||
Attribute.COLOR.getDefaultValue());
|
||||
}
|
||||
}
|
||||
return cv.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the border width for the given side.
|
||||
*/
|
||||
private int getBorderWidth(int side) {
|
||||
int width = 0;
|
||||
BorderStyle bs = (BorderStyle) attrs.getAttribute(
|
||||
ATTRIBUTES[STYLE][side]);
|
||||
if ((bs != null) && (bs.getValue() != Value.NONE)) {
|
||||
// The 'border-style' value of "none" forces the computed value
|
||||
// of 'border-width' to be 0 (CSS2 8.5.3)
|
||||
LengthValue bw = (LengthValue) attrs.getAttribute(
|
||||
ATTRIBUTES[WIDTH][side]);
|
||||
if (bw == null) {
|
||||
bw = (LengthValue) DEFAULTS[WIDTH];
|
||||
}
|
||||
width = (int) bw.getValue(true);
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of border widths in the TOP, RIGHT, BOTTOM, LEFT order.
|
||||
*/
|
||||
private int[] getWidths() {
|
||||
int[] widths = new int[4];
|
||||
for (int i = 0; i < widths.length; i++) {
|
||||
widths[i] = getBorderWidth(i);
|
||||
}
|
||||
return widths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the border style for the given side.
|
||||
*/
|
||||
private Value getBorderStyle(int side) {
|
||||
BorderStyle style =
|
||||
(BorderStyle) attrs.getAttribute(ATTRIBUTES[STYLE][side]);
|
||||
if (style == null) {
|
||||
style = (BorderStyle) DEFAULTS[STYLE];
|
||||
}
|
||||
return style.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return border shape for {@code side} as if the border has zero interior
|
||||
* length. Shape start is at (0,0); points are added clockwise.
|
||||
*/
|
||||
private Polygon getBorderShape(int side) {
|
||||
Polygon shape = null;
|
||||
int[] widths = getWidths();
|
||||
if (widths[side] != 0) {
|
||||
shape = new Polygon(new int[4], new int[4], 0);
|
||||
shape.addPoint(0, 0);
|
||||
shape.addPoint(-widths[(side + 3) % 4], -widths[side]);
|
||||
shape.addPoint(widths[(side + 1) % 4], -widths[side]);
|
||||
shape.addPoint(0, 0);
|
||||
}
|
||||
return shape;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the border painter appropriate for the given side.
|
||||
*/
|
||||
private BorderPainter getBorderPainter(int side) {
|
||||
Value style = getBorderStyle(side);
|
||||
return borderPainters.get(style);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the color with brightness adjusted by the specified factor.
|
||||
*
|
||||
* The factor values are between 0.0 (no change) and 1.0 (turn into white).
|
||||
* Negative factor values decrease brigthness (ie, 1.0 turns into black).
|
||||
*/
|
||||
static Color getAdjustedColor(Color c, double factor) {
|
||||
double f = 1 - Math.min(Math.abs(factor), 1);
|
||||
double inc = (factor > 0 ? 255 * (1 - f) : 0);
|
||||
return new Color((int) (c.getRed() * f + inc),
|
||||
(int) (c.getGreen() * f + inc),
|
||||
(int) (c.getBlue() * f + inc));
|
||||
}
|
||||
|
||||
|
||||
/* The javax.swing.border.Border methods. */
|
||||
|
||||
public Insets getBorderInsets(Component c, Insets insets) {
|
||||
int[] widths = getWidths();
|
||||
insets.set(widths[TOP], widths[LEFT], widths[BOTTOM], widths[RIGHT]);
|
||||
return insets;
|
||||
}
|
||||
|
||||
public void paintBorder(Component c, Graphics g,
|
||||
int x, int y, int width, int height) {
|
||||
if (!(g instanceof Graphics2D)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
|
||||
int[] widths = getWidths();
|
||||
|
||||
// Position and size of the border interior.
|
||||
int intX = x + widths[LEFT];
|
||||
int intY = y + widths[TOP];
|
||||
int intWidth = width - (widths[RIGHT] + widths[LEFT]);
|
||||
int intHeight = height - (widths[TOP] + widths[BOTTOM]);
|
||||
|
||||
// Coordinates of the interior corners, from NW clockwise.
|
||||
int[][] intCorners = {
|
||||
{ intX, intY },
|
||||
{ intX + intWidth, intY },
|
||||
{ intX + intWidth, intY + intHeight },
|
||||
{ intX, intY + intHeight, },
|
||||
};
|
||||
|
||||
// Draw the borders for all sides.
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Value style = getBorderStyle(i);
|
||||
Polygon shape = getBorderShape(i);
|
||||
if ((style != Value.NONE) && (shape != null)) {
|
||||
int sideLength = (i % 2 == 0 ? intWidth : intHeight);
|
||||
|
||||
// "stretch" the border shape by the interior area dimension
|
||||
shape.xpoints[2] += sideLength;
|
||||
shape.xpoints[3] += sideLength;
|
||||
Color color = getBorderColor(i);
|
||||
BorderPainter painter = getBorderPainter(i);
|
||||
|
||||
double angle = i * Math.PI / 2;
|
||||
g2.setClip(g.getClip()); // Restore initial clip
|
||||
g2.translate(intCorners[i][0], intCorners[i][1]);
|
||||
g2.rotate(angle);
|
||||
g2.clip(shape);
|
||||
painter.paint(shape, g2, color, i);
|
||||
g2.rotate(-angle);
|
||||
g2.translate(-intCorners[i][0], -intCorners[i][1]);
|
||||
}
|
||||
}
|
||||
g2.dispose();
|
||||
}
|
||||
|
||||
|
||||
/* Border painters. */
|
||||
|
||||
interface BorderPainter {
|
||||
/**
|
||||
* The painter should paint the border as if it were at the top and the
|
||||
* coordinates of the NW corner of the interior area is (0, 0). The
|
||||
* caller is responsible for the appropriate affine transformations.
|
||||
*
|
||||
* Clip is set by the caller to the exact border shape so it's safe to
|
||||
* simply draw into the shape's bounding rectangle.
|
||||
*/
|
||||
void paint(Polygon shape, Graphics g, Color color, int side);
|
||||
}
|
||||
|
||||
/**
|
||||
* Painter for the "none" and "hidden" CSS border styles.
|
||||
*/
|
||||
static class NullPainter implements BorderPainter {
|
||||
public void paint(Polygon shape, Graphics g, Color color, int side) {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Painter for the "solid" CSS border style.
|
||||
*/
|
||||
static class SolidPainter implements BorderPainter {
|
||||
public void paint(Polygon shape, Graphics g, Color color, int side) {
|
||||
g.setColor(color);
|
||||
g.fillPolygon(shape);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a method for painting strokes in the specified direction using
|
||||
* the given length and color patterns.
|
||||
*/
|
||||
abstract static class StrokePainter implements BorderPainter {
|
||||
/**
|
||||
* Paint strokes repeatedly using the given length and color patterns.
|
||||
*/
|
||||
void paintStrokes(Rectangle r, Graphics g, int axis,
|
||||
int[] lengthPattern, Color[] colorPattern) {
|
||||
boolean xAxis = (axis == View.X_AXIS);
|
||||
int start = 0;
|
||||
int end = (xAxis ? r.width : r.height);
|
||||
while (start < end) {
|
||||
for (int i = 0; i < lengthPattern.length; i++) {
|
||||
if (start >= end) {
|
||||
break;
|
||||
}
|
||||
int length = lengthPattern[i];
|
||||
Color c = colorPattern[i];
|
||||
if (c != null) {
|
||||
int x = r.x + (xAxis ? start : 0);
|
||||
int y = r.y + (xAxis ? 0 : start);
|
||||
int width = xAxis ? length : r.width;
|
||||
int height = xAxis ? r.height : length;
|
||||
g.setColor(c);
|
||||
g.fillRect(x, y, width, height);
|
||||
}
|
||||
start += length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Painter for the "double" CSS border style.
|
||||
*/
|
||||
static class DoublePainter extends StrokePainter {
|
||||
public void paint(Polygon shape, Graphics g, Color color, int side) {
|
||||
Rectangle r = shape.getBounds();
|
||||
int length = Math.max(r.height / 3, 1);
|
||||
int[] lengthPattern = { length, length };
|
||||
Color[] colorPattern = { color, null };
|
||||
paintStrokes(r, g, View.Y_AXIS, lengthPattern, colorPattern);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Painter for the "dotted" and "dashed" CSS border styles.
|
||||
*/
|
||||
static class DottedDashedPainter extends StrokePainter {
|
||||
final int factor;
|
||||
|
||||
DottedDashedPainter(int factor) {
|
||||
this.factor = factor;
|
||||
}
|
||||
|
||||
public void paint(Polygon shape, Graphics g, Color color, int side) {
|
||||
Rectangle r = shape.getBounds();
|
||||
int length = r.height * factor;
|
||||
int[] lengthPattern = { length, length };
|
||||
Color[] colorPattern = { color, null };
|
||||
paintStrokes(r, g, View.X_AXIS, lengthPattern, colorPattern);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Painter that defines colors for "shadow" and "light" border sides.
|
||||
*/
|
||||
abstract static class ShadowLightPainter extends StrokePainter {
|
||||
/**
|
||||
* Return the "shadow" border side color.
|
||||
*/
|
||||
static Color getShadowColor(Color c) {
|
||||
return CSSBorder.getAdjustedColor(c, -0.3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the "light" border side color.
|
||||
*/
|
||||
static Color getLightColor(Color c) {
|
||||
return CSSBorder.getAdjustedColor(c, 0.7);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Painter for the "groove" and "ridge" CSS border styles.
|
||||
*/
|
||||
static class GrooveRidgePainter extends ShadowLightPainter {
|
||||
final Value type;
|
||||
|
||||
GrooveRidgePainter(Value type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void paint(Polygon shape, Graphics g, Color color, int side) {
|
||||
Rectangle r = shape.getBounds();
|
||||
int length = Math.max(r.height / 2, 1);
|
||||
int[] lengthPattern = { length, length };
|
||||
Color[] colorPattern =
|
||||
((side + 1) % 4 < 2) == (type == Value.GROOVE) ?
|
||||
new Color[] { getShadowColor(color), getLightColor(color) } :
|
||||
new Color[] { getLightColor(color), getShadowColor(color) };
|
||||
paintStrokes(r, g, View.Y_AXIS, lengthPattern, colorPattern);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Painter for the "inset" and "outset" CSS border styles.
|
||||
*/
|
||||
static class InsetOutsetPainter extends ShadowLightPainter {
|
||||
Value type;
|
||||
|
||||
InsetOutsetPainter(Value type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void paint(Polygon shape, Graphics g, Color color, int side) {
|
||||
g.setColor(((side + 1) % 4 < 2) == (type == Value.INSET) ?
|
||||
getShadowColor(color) : getLightColor(color));
|
||||
g.fillPolygon(shape);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the specified painter to the painters map.
|
||||
*/
|
||||
static void registerBorderPainter(Value style, BorderPainter painter) {
|
||||
borderPainters.put(style, painter);
|
||||
}
|
||||
|
||||
/** Map the border style values to the border painter objects. */
|
||||
static Map<Value, BorderPainter> borderPainters =
|
||||
new HashMap<Value, BorderPainter>();
|
||||
|
||||
/* Initialize the border painters map with the pre-defined values. */
|
||||
static {
|
||||
registerBorderPainter(Value.NONE, new NullPainter());
|
||||
registerBorderPainter(Value.HIDDEN, new NullPainter());
|
||||
registerBorderPainter(Value.SOLID, new SolidPainter());
|
||||
registerBorderPainter(Value.DOUBLE, new DoublePainter());
|
||||
registerBorderPainter(Value.DOTTED, new DottedDashedPainter(1));
|
||||
registerBorderPainter(Value.DASHED, new DottedDashedPainter(3));
|
||||
registerBorderPainter(Value.GROOVE, new GrooveRidgePainter(Value.GROOVE));
|
||||
registerBorderPainter(Value.RIDGE, new GrooveRidgePainter(Value.RIDGE));
|
||||
registerBorderPainter(Value.INSET, new InsetOutsetPainter(Value.INSET));
|
||||
registerBorderPainter(Value.OUTSET, new InsetOutsetPainter(Value.OUTSET));
|
||||
}
|
||||
}
|
||||
854
jdkSrc/jdk8/javax/swing/text/html/CSSParser.java
Normal file
854
jdkSrc/jdk8/javax/swing/text/html/CSSParser.java
Normal file
@@ -0,0 +1,854 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* A CSS parser. This works by way of a delegate that implements the
|
||||
* CSSParserCallback interface. The delegate is notified of the following
|
||||
* events:
|
||||
* <ul>
|
||||
* <li>Import statement: <code>handleImport</code>
|
||||
* <li>Selectors <code>handleSelector</code>. 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'.
|
||||
* <li>When a rule starts, <code>startRule</code>
|
||||
* <li>Properties in the rule via the <code>handleProperty</code>. 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'.
|
||||
* <li>Values in the rule via the <code>handleValue</code>, this is notified
|
||||
* for the total value.
|
||||
* <li>When a rule ends, <code>endRule</code>
|
||||
* </ul>
|
||||
* This will parse much more than CSS 1, and loosely implements the
|
||||
* recommendation for <i>Forward-compatible parsing</i> in section
|
||||
* 7.1 of the CSS spec found at:
|
||||
* <a href=http://www.w3.org/TR/REC-CSS1>http://www.w3.org/TR/REC-CSS1</a>.
|
||||
* If an error results in parsing, a RuntimeException will be thrown.
|
||||
* <p>
|
||||
* This will preserve case. If the callback wishes to treat certain poritions
|
||||
* case insensitively (such as selectors), it should use toLowerCase, or
|
||||
* something similar.
|
||||
*
|
||||
* @author Scott Violet
|
||||
*/
|
||||
class CSSParser {
|
||||
// Parsing something like the following:
|
||||
// (@rule | ruleset | block)*
|
||||
//
|
||||
// @rule (block | identifier)*; (block with {} ends @rule)
|
||||
// block matching [] () {} (that is, [()] is a block, [(){}{[]}]
|
||||
// is a block, ()[] is two blocks)
|
||||
// identifier "*" | '*' | anything but a [](){} and whitespace
|
||||
//
|
||||
// ruleset selector decblock
|
||||
// selector (identifier | (block, except block '{}') )*
|
||||
// declblock declaration* block*
|
||||
// declaration (identifier* stopping when identifier ends with :)
|
||||
// (identifier* stopping when identifier ends with ;)
|
||||
//
|
||||
// comments /* */ can appear any where, and are stripped.
|
||||
|
||||
|
||||
// identifier - letters, digits, dashes and escaped characters
|
||||
// block starts with { ends with matching }, () [] and {} always occur
|
||||
// in matching pairs, '' and "" also occur in pairs, except " may be
|
||||
|
||||
|
||||
// Indicates the type of token being parsed.
|
||||
private static final int IDENTIFIER = 1;
|
||||
private static final int BRACKET_OPEN = 2;
|
||||
private static final int BRACKET_CLOSE = 3;
|
||||
private static final int BRACE_OPEN = 4;
|
||||
private static final int BRACE_CLOSE = 5;
|
||||
private static final int PAREN_OPEN = 6;
|
||||
private static final int PAREN_CLOSE = 7;
|
||||
private static final int END = -1;
|
||||
|
||||
private static final char[] charMapping = { 0, 0, '[', ']', '{', '}', '(',
|
||||
')', 0};
|
||||
|
||||
|
||||
/** Set to true if one character has been read ahead. */
|
||||
private boolean didPushChar;
|
||||
/** The read ahead character. */
|
||||
private int pushedChar;
|
||||
/** Temporary place to hold identifiers. */
|
||||
private StringBuffer unitBuffer;
|
||||
/** 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;
|
||||
/** Notified of state. */
|
||||
private 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;
|
||||
|
||||
|
||||
// The delegate interface.
|
||||
static interface CSSParserCallback {
|
||||
/** Called when an @import is encountered. */
|
||||
void handleImport(String importString);
|
||||
// There is currently no way to distinguish between '"foo,"' and
|
||||
// 'foo,'. But this generally isn't valid CSS. If it becomes
|
||||
// a problem, handleSelector will have to be told if the string is
|
||||
// quoted.
|
||||
void handleSelector(String selector);
|
||||
void startRule();
|
||||
// Property names are mapped to lower case before being passed to
|
||||
// the delegate.
|
||||
void handleProperty(String property);
|
||||
void handleValue(String value);
|
||||
void endRule();
|
||||
}
|
||||
|
||||
CSSParser() {
|
||||
unitStack = new int[2];
|
||||
tokenBuffer = new char[80];
|
||||
unitBuffer = new StringBuffer();
|
||||
}
|
||||
|
||||
void parse(Reader reader, CSSParserCallback callback,
|
||||
boolean inRule) throws IOException {
|
||||
this.callback = callback;
|
||||
stackCount = tokenBufferLength = 0;
|
||||
this.reader = reader;
|
||||
encounteredRuleSet = false;
|
||||
try {
|
||||
if (inRule) {
|
||||
parseDeclarationBlock();
|
||||
}
|
||||
else {
|
||||
while (getNextStatement());
|
||||
}
|
||||
} finally {
|
||||
callback = null;
|
||||
reader = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next statement, returning false if the end is reached. A
|
||||
* statement is either an @rule, or a ruleset.
|
||||
*/
|
||||
private boolean getNextStatement() throws IOException {
|
||||
unitBuffer.setLength(0);
|
||||
|
||||
int token = nextToken((char)0);
|
||||
|
||||
switch (token) {
|
||||
case IDENTIFIER:
|
||||
if (tokenBufferLength > 0) {
|
||||
if (tokenBuffer[0] == '@') {
|
||||
parseAtRule();
|
||||
}
|
||||
else {
|
||||
encounteredRuleSet = true;
|
||||
parseRuleSet();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case BRACKET_OPEN:
|
||||
case BRACE_OPEN:
|
||||
case PAREN_OPEN:
|
||||
parseTillClosed(token);
|
||||
return true;
|
||||
|
||||
case BRACKET_CLOSE:
|
||||
case BRACE_CLOSE:
|
||||
case PAREN_CLOSE:
|
||||
// Shouldn't happen...
|
||||
throw new RuntimeException("Unexpected top level block close");
|
||||
|
||||
case END:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an @ rule, stopping at a matching brace pair, or ;.
|
||||
*/
|
||||
private void parseAtRule() throws IOException {
|
||||
// PENDING: make this more effecient.
|
||||
boolean done = false;
|
||||
boolean isImport = (tokenBufferLength == 7 &&
|
||||
tokenBuffer[0] == '@' && tokenBuffer[1] == 'i' &&
|
||||
tokenBuffer[2] == 'm' && tokenBuffer[3] == 'p' &&
|
||||
tokenBuffer[4] == 'o' && tokenBuffer[5] == 'r' &&
|
||||
tokenBuffer[6] == 't');
|
||||
|
||||
unitBuffer.setLength(0);
|
||||
while (!done) {
|
||||
int nextToken = nextToken(';');
|
||||
|
||||
switch (nextToken) {
|
||||
case IDENTIFIER:
|
||||
if (tokenBufferLength > 0 &&
|
||||
tokenBuffer[tokenBufferLength - 1] == ';') {
|
||||
--tokenBufferLength;
|
||||
done = true;
|
||||
}
|
||||
if (tokenBufferLength > 0) {
|
||||
if (unitBuffer.length() > 0 && readWS) {
|
||||
unitBuffer.append(' ');
|
||||
}
|
||||
unitBuffer.append(tokenBuffer, 0, tokenBufferLength);
|
||||
}
|
||||
break;
|
||||
|
||||
case BRACE_OPEN:
|
||||
if (unitBuffer.length() > 0 && readWS) {
|
||||
unitBuffer.append(' ');
|
||||
}
|
||||
unitBuffer.append(charMapping[nextToken]);
|
||||
parseTillClosed(nextToken);
|
||||
done = true;
|
||||
// Skip a tailing ';', not really to spec.
|
||||
{
|
||||
int nextChar = readWS();
|
||||
if (nextChar != -1 && nextChar != ';') {
|
||||
pushChar(nextChar);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BRACKET_OPEN: case PAREN_OPEN:
|
||||
unitBuffer.append(charMapping[nextToken]);
|
||||
parseTillClosed(nextToken);
|
||||
break;
|
||||
|
||||
case BRACKET_CLOSE: case BRACE_CLOSE: case PAREN_CLOSE:
|
||||
throw new RuntimeException("Unexpected close in @ rule");
|
||||
|
||||
case END:
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isImport && !encounteredRuleSet) {
|
||||
callback.handleImport(unitBuffer.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the next rule set, which is a selector followed by a
|
||||
* declaration block.
|
||||
*/
|
||||
private void parseRuleSet() throws IOException {
|
||||
if (parseSelectors()) {
|
||||
callback.startRule();
|
||||
parseDeclarationBlock();
|
||||
callback.endRule();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a set of selectors, returning false if the end of the stream
|
||||
* is reached.
|
||||
*/
|
||||
private boolean parseSelectors() throws IOException {
|
||||
// Parse the selectors
|
||||
int nextToken;
|
||||
|
||||
if (tokenBufferLength > 0) {
|
||||
callback.handleSelector(new String(tokenBuffer, 0,
|
||||
tokenBufferLength));
|
||||
}
|
||||
|
||||
unitBuffer.setLength(0);
|
||||
for (;;) {
|
||||
while ((nextToken = nextToken((char)0)) == IDENTIFIER) {
|
||||
if (tokenBufferLength > 0) {
|
||||
callback.handleSelector(new String(tokenBuffer, 0,
|
||||
tokenBufferLength));
|
||||
}
|
||||
}
|
||||
switch (nextToken) {
|
||||
case BRACE_OPEN:
|
||||
return true;
|
||||
|
||||
case BRACKET_OPEN: case PAREN_OPEN:
|
||||
parseTillClosed(nextToken);
|
||||
// Not too sure about this, how we handle this isn't very
|
||||
// well spec'd.
|
||||
unitBuffer.setLength(0);
|
||||
break;
|
||||
|
||||
case BRACKET_CLOSE: case BRACE_CLOSE: case PAREN_CLOSE:
|
||||
throw new RuntimeException("Unexpected block close in selector");
|
||||
|
||||
case END:
|
||||
// Prematurely hit end.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a declaration block. Which a number of declarations followed
|
||||
* by a })].
|
||||
*/
|
||||
private void parseDeclarationBlock() throws IOException {
|
||||
for (;;) {
|
||||
int token = parseDeclaration();
|
||||
switch (token) {
|
||||
case END: case BRACE_CLOSE:
|
||||
return;
|
||||
|
||||
case BRACKET_CLOSE: case PAREN_CLOSE:
|
||||
// Bail
|
||||
throw new RuntimeException("Unexpected close in declaration block");
|
||||
case IDENTIFIER:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a single declaration, which is an identifier a : and another
|
||||
* identifier. This returns the last token seen.
|
||||
*/
|
||||
// identifier+: identifier* ;|}
|
||||
private int parseDeclaration() throws IOException {
|
||||
int token;
|
||||
|
||||
if ((token = parseIdentifiers(':', false)) != IDENTIFIER) {
|
||||
return token;
|
||||
}
|
||||
// Make the property name to lowercase
|
||||
for (int counter = unitBuffer.length() - 1; counter >= 0; counter--) {
|
||||
unitBuffer.setCharAt(counter, Character.toLowerCase
|
||||
(unitBuffer.charAt(counter)));
|
||||
}
|
||||
callback.handleProperty(unitBuffer.toString());
|
||||
|
||||
token = parseIdentifiers(';', true);
|
||||
callback.handleValue(unitBuffer.toString());
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses identifiers until <code>extraChar</code> is encountered,
|
||||
* returning the ending token, which will be IDENTIFIER if extraChar
|
||||
* is found.
|
||||
*/
|
||||
private int parseIdentifiers(char extraChar,
|
||||
boolean wantsBlocks) throws IOException {
|
||||
int nextToken;
|
||||
int ubl;
|
||||
|
||||
unitBuffer.setLength(0);
|
||||
for (;;) {
|
||||
nextToken = nextToken(extraChar);
|
||||
|
||||
switch (nextToken) {
|
||||
case IDENTIFIER:
|
||||
if (tokenBufferLength > 0) {
|
||||
if (tokenBuffer[tokenBufferLength - 1] == extraChar) {
|
||||
if (--tokenBufferLength > 0) {
|
||||
if (readWS && unitBuffer.length() > 0) {
|
||||
unitBuffer.append(' ');
|
||||
}
|
||||
unitBuffer.append(tokenBuffer, 0,
|
||||
tokenBufferLength);
|
||||
}
|
||||
return IDENTIFIER;
|
||||
}
|
||||
if (readWS && unitBuffer.length() > 0) {
|
||||
unitBuffer.append(' ');
|
||||
}
|
||||
unitBuffer.append(tokenBuffer, 0, tokenBufferLength);
|
||||
}
|
||||
break;
|
||||
|
||||
case BRACKET_OPEN:
|
||||
case BRACE_OPEN:
|
||||
case PAREN_OPEN:
|
||||
ubl = unitBuffer.length();
|
||||
if (wantsBlocks) {
|
||||
unitBuffer.append(charMapping[nextToken]);
|
||||
}
|
||||
parseTillClosed(nextToken);
|
||||
if (!wantsBlocks) {
|
||||
unitBuffer.setLength(ubl);
|
||||
}
|
||||
break;
|
||||
|
||||
case BRACE_CLOSE:
|
||||
// No need to throw for these two, we return token and
|
||||
// caller can do whatever.
|
||||
case BRACKET_CLOSE:
|
||||
case PAREN_CLOSE:
|
||||
case END:
|
||||
// Hit the end
|
||||
return nextToken;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses till a matching block close is encountered. This is only
|
||||
* appropriate to be called at the top level (no nesting).
|
||||
*/
|
||||
private void parseTillClosed(int openToken) throws IOException {
|
||||
int nextToken;
|
||||
boolean done = false;
|
||||
|
||||
startBlock(openToken);
|
||||
while (!done) {
|
||||
nextToken = nextToken((char)0);
|
||||
switch (nextToken) {
|
||||
case IDENTIFIER:
|
||||
if (unitBuffer.length() > 0 && readWS) {
|
||||
unitBuffer.append(' ');
|
||||
}
|
||||
if (tokenBufferLength > 0) {
|
||||
unitBuffer.append(tokenBuffer, 0, tokenBufferLength);
|
||||
}
|
||||
break;
|
||||
|
||||
case BRACKET_OPEN: case BRACE_OPEN: case PAREN_OPEN:
|
||||
if (unitBuffer.length() > 0 && readWS) {
|
||||
unitBuffer.append(' ');
|
||||
}
|
||||
unitBuffer.append(charMapping[nextToken]);
|
||||
startBlock(nextToken);
|
||||
break;
|
||||
|
||||
case BRACKET_CLOSE: case BRACE_CLOSE: case PAREN_CLOSE:
|
||||
if (unitBuffer.length() > 0 && readWS) {
|
||||
unitBuffer.append(' ');
|
||||
}
|
||||
unitBuffer.append(charMapping[nextToken]);
|
||||
endBlock(nextToken);
|
||||
if (!inBlock()) {
|
||||
done = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case END:
|
||||
// Prematurely hit end.
|
||||
throw new RuntimeException("Unclosed block");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the next token.
|
||||
*/
|
||||
private int nextToken(char idChar) throws IOException {
|
||||
readWS = false;
|
||||
|
||||
int nextChar = readWS();
|
||||
|
||||
switch (nextChar) {
|
||||
case '\'':
|
||||
readTill('\'');
|
||||
if (tokenBufferLength > 0) {
|
||||
tokenBufferLength--;
|
||||
}
|
||||
return IDENTIFIER;
|
||||
case '"':
|
||||
readTill('"');
|
||||
if (tokenBufferLength > 0) {
|
||||
tokenBufferLength--;
|
||||
}
|
||||
return IDENTIFIER;
|
||||
case '[':
|
||||
return BRACKET_OPEN;
|
||||
case ']':
|
||||
return BRACKET_CLOSE;
|
||||
case '{':
|
||||
return BRACE_OPEN;
|
||||
case '}':
|
||||
return BRACE_CLOSE;
|
||||
case '(':
|
||||
return PAREN_OPEN;
|
||||
case ')':
|
||||
return PAREN_CLOSE;
|
||||
case -1:
|
||||
return END;
|
||||
default:
|
||||
pushChar(nextChar);
|
||||
getIdentifier(idChar);
|
||||
return IDENTIFIER;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an identifier, returning true if the length of the string is greater than 0,
|
||||
* stopping when <code>stopChar</code>, whitespace, or one of {}()[] is
|
||||
* hit.
|
||||
*/
|
||||
// NOTE: this could be combined with readTill, as they contain somewhat
|
||||
// similar functionality.
|
||||
private boolean getIdentifier(char stopChar) throws IOException {
|
||||
boolean lastWasEscape = false;
|
||||
boolean done = false;
|
||||
int escapeCount = 0;
|
||||
int escapeChar = 0;
|
||||
int nextChar;
|
||||
int intStopChar = (int)stopChar;
|
||||
// 1 for '\', 2 for valid escape char [0-9a-fA-F], 3 for
|
||||
// stop character (white space, ()[]{}) 0 otherwise
|
||||
short type;
|
||||
int escapeOffset = 0;
|
||||
|
||||
tokenBufferLength = 0;
|
||||
while (!done) {
|
||||
nextChar = readChar();
|
||||
switch (nextChar) {
|
||||
case '\\':
|
||||
type = 1;
|
||||
break;
|
||||
|
||||
case '0': case '1': case '2': case '3': case '4': case '5':
|
||||
case '6': case '7': case '8': case '9':
|
||||
type = 2;
|
||||
escapeOffset = nextChar - '0';
|
||||
break;
|
||||
|
||||
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
|
||||
type = 2;
|
||||
escapeOffset = nextChar - 'a' + 10;
|
||||
break;
|
||||
|
||||
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
|
||||
type = 2;
|
||||
escapeOffset = nextChar - 'A' + 10;
|
||||
break;
|
||||
|
||||
case '\'': case '"': case '[': case ']': case '{': case '}':
|
||||
case '(': case ')':
|
||||
case ' ': case '\n': case '\t': case '\r':
|
||||
type = 3;
|
||||
break;
|
||||
|
||||
case '/':
|
||||
type = 4;
|
||||
break;
|
||||
|
||||
case -1:
|
||||
// Reached the end
|
||||
done = true;
|
||||
type = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
type = 0;
|
||||
break;
|
||||
}
|
||||
if (lastWasEscape) {
|
||||
if (type == 2) {
|
||||
// Continue with escape.
|
||||
escapeChar = escapeChar * 16 + escapeOffset;
|
||||
if (++escapeCount == 4) {
|
||||
lastWasEscape = false;
|
||||
append((char)escapeChar);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// no longer escaped
|
||||
lastWasEscape = false;
|
||||
if (escapeCount > 0) {
|
||||
append((char)escapeChar);
|
||||
// Make this simpler, reprocess the character.
|
||||
pushChar(nextChar);
|
||||
}
|
||||
else if (!done) {
|
||||
append((char)nextChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!done) {
|
||||
if (type == 1) {
|
||||
lastWasEscape = true;
|
||||
escapeChar = escapeCount = 0;
|
||||
}
|
||||
else if (type == 3) {
|
||||
done = true;
|
||||
pushChar(nextChar);
|
||||
}
|
||||
else if (type == 4) {
|
||||
// Potential comment
|
||||
nextChar = readChar();
|
||||
if (nextChar == '*') {
|
||||
done = true;
|
||||
readComment();
|
||||
readWS = true;
|
||||
}
|
||||
else {
|
||||
append('/');
|
||||
if (nextChar == -1) {
|
||||
done = true;
|
||||
}
|
||||
else {
|
||||
pushChar(nextChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
append((char)nextChar);
|
||||
if (nextChar == intStopChar) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (tokenBufferLength > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads till a <code>stopChar</code> is encountered, escaping characters
|
||||
* as necessary.
|
||||
*/
|
||||
private void readTill(char stopChar) throws IOException {
|
||||
boolean lastWasEscape = false;
|
||||
int escapeCount = 0;
|
||||
int escapeChar = 0;
|
||||
int nextChar;
|
||||
boolean done = false;
|
||||
int intStopChar = (int)stopChar;
|
||||
// 1 for '\', 2 for valid escape char [0-9a-fA-F], 0 otherwise
|
||||
short type;
|
||||
int escapeOffset = 0;
|
||||
|
||||
tokenBufferLength = 0;
|
||||
while (!done) {
|
||||
nextChar = readChar();
|
||||
switch (nextChar) {
|
||||
case '\\':
|
||||
type = 1;
|
||||
break;
|
||||
|
||||
case '0': case '1': case '2': case '3': case '4':case '5':
|
||||
case '6': case '7': case '8': case '9':
|
||||
type = 2;
|
||||
escapeOffset = nextChar - '0';
|
||||
break;
|
||||
|
||||
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
|
||||
type = 2;
|
||||
escapeOffset = nextChar - 'a' + 10;
|
||||
break;
|
||||
|
||||
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
|
||||
type = 2;
|
||||
escapeOffset = nextChar - 'A' + 10;
|
||||
break;
|
||||
|
||||
case -1:
|
||||
// Prematurely reached the end!
|
||||
throw new RuntimeException("Unclosed " + stopChar);
|
||||
|
||||
default:
|
||||
type = 0;
|
||||
break;
|
||||
}
|
||||
if (lastWasEscape) {
|
||||
if (type == 2) {
|
||||
// Continue with escape.
|
||||
escapeChar = escapeChar * 16 + escapeOffset;
|
||||
if (++escapeCount == 4) {
|
||||
lastWasEscape = false;
|
||||
append((char)escapeChar);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// no longer escaped
|
||||
if (escapeCount > 0) {
|
||||
append((char)escapeChar);
|
||||
if (type == 1) {
|
||||
lastWasEscape = true;
|
||||
escapeChar = escapeCount = 0;
|
||||
}
|
||||
else {
|
||||
if (nextChar == intStopChar) {
|
||||
done = true;
|
||||
}
|
||||
append((char)nextChar);
|
||||
lastWasEscape = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
append((char)nextChar);
|
||||
lastWasEscape = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == 1) {
|
||||
lastWasEscape = true;
|
||||
escapeChar = escapeCount = 0;
|
||||
}
|
||||
else {
|
||||
if (nextChar == intStopChar) {
|
||||
done = true;
|
||||
}
|
||||
append((char)nextChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void append(char character) {
|
||||
if (tokenBufferLength == tokenBuffer.length) {
|
||||
char[] newBuffer = new char[tokenBuffer.length * 2];
|
||||
System.arraycopy(tokenBuffer, 0, newBuffer, 0, tokenBuffer.length);
|
||||
tokenBuffer = newBuffer;
|
||||
}
|
||||
tokenBuffer[tokenBufferLength++] = character;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a comment block.
|
||||
*/
|
||||
private void readComment() throws IOException {
|
||||
int nextChar;
|
||||
|
||||
for(;;) {
|
||||
nextChar = readChar();
|
||||
switch (nextChar) {
|
||||
case -1:
|
||||
throw new RuntimeException("Unclosed comment");
|
||||
case '*':
|
||||
nextChar = readChar();
|
||||
if (nextChar == '/') {
|
||||
return;
|
||||
}
|
||||
else if (nextChar == -1) {
|
||||
throw new RuntimeException("Unclosed comment");
|
||||
}
|
||||
else {
|
||||
pushChar(nextChar);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a block start is encountered ({[.
|
||||
*/
|
||||
private void startBlock(int startToken) {
|
||||
if (stackCount == unitStack.length) {
|
||||
int[] newUS = new int[stackCount * 2];
|
||||
|
||||
System.arraycopy(unitStack, 0, newUS, 0, stackCount);
|
||||
unitStack = newUS;
|
||||
}
|
||||
unitStack[stackCount++] = startToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an end block is encountered )]}
|
||||
*/
|
||||
private void endBlock(int endToken) {
|
||||
int startToken;
|
||||
|
||||
switch (endToken) {
|
||||
case BRACKET_CLOSE:
|
||||
startToken = BRACKET_OPEN;
|
||||
break;
|
||||
case BRACE_CLOSE:
|
||||
startToken = BRACE_OPEN;
|
||||
break;
|
||||
case PAREN_CLOSE:
|
||||
startToken = PAREN_OPEN;
|
||||
break;
|
||||
default:
|
||||
// Will never happen.
|
||||
startToken = -1;
|
||||
break;
|
||||
}
|
||||
if (stackCount > 0 && unitStack[stackCount - 1] == startToken) {
|
||||
stackCount--;
|
||||
}
|
||||
else {
|
||||
// Invalid state, should do something.
|
||||
throw new RuntimeException("Unmatched block");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if currently in a block.
|
||||
*/
|
||||
private boolean inBlock() {
|
||||
return (stackCount > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips any white space, returning the character after the white space.
|
||||
*/
|
||||
private int readWS() throws IOException {
|
||||
int nextChar;
|
||||
while ((nextChar = readChar()) != -1 &&
|
||||
Character.isWhitespace((char)nextChar)) {
|
||||
readWS = true;
|
||||
}
|
||||
return nextChar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a character from the stream.
|
||||
*/
|
||||
private int readChar() throws IOException {
|
||||
if (didPushChar) {
|
||||
didPushChar = false;
|
||||
return pushedChar;
|
||||
}
|
||||
return reader.read();
|
||||
// Uncomment the following to do case insensitive parsing.
|
||||
/*
|
||||
if (retValue != -1) {
|
||||
return (int)Character.toLowerCase((char)retValue);
|
||||
}
|
||||
return retValue;
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Supports one character look ahead, this will throw if called twice
|
||||
* in a row.
|
||||
*/
|
||||
private void pushChar(int tempChar) {
|
||||
if (didPushChar) {
|
||||
// Should never happen.
|
||||
throw new RuntimeException("Can not handle look ahead of more than one character");
|
||||
}
|
||||
didPushChar = true;
|
||||
pushedChar = tempChar;
|
||||
}
|
||||
}
|
||||
141
jdkSrc/jdk8/javax/swing/text/html/CommentView.java
Normal file
141
jdkSrc/jdk8/javax/swing/text/html/CommentView.java
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.*;
|
||||
import javax.swing.event.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* CommentView subclasses HiddenTagView to contain a JTextArea showing
|
||||
* a comment. When the textarea is edited the comment is
|
||||
* reset. As this inherits from EditableView if the JTextComponent is
|
||||
* not editable, the textarea will not be visible.
|
||||
*
|
||||
* @author Scott Violet
|
||||
*/
|
||||
class CommentView extends HiddenTagView {
|
||||
CommentView(Element e) {
|
||||
super(e);
|
||||
}
|
||||
|
||||
protected Component createComponent() {
|
||||
Container host = getContainer();
|
||||
if (host != null && !((JTextComponent)host).isEditable()) {
|
||||
return null;
|
||||
}
|
||||
JTextArea ta = new JTextArea(getRepresentedText());
|
||||
Document doc = getDocument();
|
||||
Font font;
|
||||
if (doc instanceof StyledDocument) {
|
||||
font = ((StyledDocument)doc).getFont(getAttributes());
|
||||
ta.setFont(font);
|
||||
}
|
||||
else {
|
||||
font = ta.getFont();
|
||||
}
|
||||
updateYAlign(font);
|
||||
ta.setBorder(CBorder);
|
||||
ta.getDocument().addDocumentListener(this);
|
||||
ta.setFocusable(isVisible());
|
||||
return ta;
|
||||
}
|
||||
|
||||
void resetBorder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This is subclassed to put the text on the Comment attribute of
|
||||
* the Element's AttributeSet.
|
||||
*/
|
||||
void _updateModelFromText() {
|
||||
JTextComponent textC = getTextComponent();
|
||||
Document doc = getDocument();
|
||||
if (textC != null && doc != null) {
|
||||
String text = textC.getText();
|
||||
SimpleAttributeSet sas = new SimpleAttributeSet();
|
||||
isSettingAttributes = true;
|
||||
try {
|
||||
sas.addAttribute(HTML.Attribute.COMMENT, text);
|
||||
((StyledDocument)doc).setCharacterAttributes
|
||||
(getStartOffset(), getEndOffset() -
|
||||
getStartOffset(), sas, false);
|
||||
}
|
||||
finally {
|
||||
isSettingAttributes = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JTextComponent getTextComponent() {
|
||||
return (JTextComponent)getComponent();
|
||||
}
|
||||
|
||||
String getRepresentedText() {
|
||||
AttributeSet as = getElement().getAttributes();
|
||||
if (as != null) {
|
||||
Object comment = as.getAttribute(HTML.Attribute.COMMENT);
|
||||
if (comment instanceof String) {
|
||||
return (String)comment;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static final Border CBorder = new CommentBorder();
|
||||
static final int commentPadding = 3;
|
||||
static final int commentPaddingD = commentPadding * 3;
|
||||
|
||||
static class CommentBorder extends LineBorder {
|
||||
CommentBorder() {
|
||||
super(Color.black, 1);
|
||||
}
|
||||
|
||||
public void paintBorder(Component c, Graphics g, int x, int y,
|
||||
int width, int height) {
|
||||
super.paintBorder(c, g, x + commentPadding, y,
|
||||
width - commentPaddingD, height);
|
||||
}
|
||||
|
||||
public Insets getBorderInsets(Component c, Insets insets) {
|
||||
Insets retI = super.getBorderInsets(c, insets);
|
||||
|
||||
retI.left += commentPadding;
|
||||
retI.right += commentPadding;
|
||||
return retI;
|
||||
}
|
||||
|
||||
public boolean isBorderOpaque() {
|
||||
return false;
|
||||
}
|
||||
} // End of class CommentView.CommentBorder
|
||||
} // End of CommentView
|
||||
128
jdkSrc/jdk8/javax/swing/text/html/EditableView.java
Normal file
128
jdkSrc/jdk8/javax/swing/text/html/EditableView.java
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.*;
|
||||
import javax.swing.event.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* EditableView sets the view it contains to be visible only when the
|
||||
* JTextComponent the view is contained in is editable. The min/pref/max
|
||||
* size is 0 when not visible.
|
||||
*
|
||||
* @author Scott Violet
|
||||
*/
|
||||
class EditableView extends ComponentView {
|
||||
|
||||
EditableView(Element e) {
|
||||
super(e);
|
||||
}
|
||||
|
||||
public float getMinimumSpan(int axis) {
|
||||
if (isVisible) {
|
||||
return super.getMinimumSpan(axis);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public float getPreferredSpan(int axis) {
|
||||
if (isVisible) {
|
||||
return super.getPreferredSpan(axis);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public float getMaximumSpan(int axis) {
|
||||
if (isVisible) {
|
||||
return super.getMaximumSpan(axis);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void paint(Graphics g, Shape allocation) {
|
||||
Component c = getComponent();
|
||||
Container host = getContainer();
|
||||
|
||||
if (host instanceof JTextComponent &&
|
||||
isVisible != ((JTextComponent)host).isEditable()) {
|
||||
isVisible = ((JTextComponent)host).isEditable();
|
||||
preferenceChanged(null, true, true);
|
||||
host.repaint();
|
||||
}
|
||||
/*
|
||||
* Note: we cannot tweak the visible state of the
|
||||
* component in createComponent() even though it
|
||||
* gets called after the setParent() call where
|
||||
* the value of the boolean is set. This
|
||||
* because, the setComponentParent() in the
|
||||
* superclass, always does a setVisible(false)
|
||||
* after calling createComponent(). We therefore
|
||||
* use this flag in the paint() method to
|
||||
* setVisible() to true if required.
|
||||
*/
|
||||
if (isVisible) {
|
||||
super.paint(g, allocation);
|
||||
}
|
||||
else {
|
||||
setSize(0, 0);
|
||||
}
|
||||
if (c != null) {
|
||||
c.setFocusable(isVisible);
|
||||
}
|
||||
}
|
||||
|
||||
public void setParent(View parent) {
|
||||
if (parent != null) {
|
||||
Container host = parent.getContainer();
|
||||
if (host != null) {
|
||||
if (host instanceof JTextComponent) {
|
||||
isVisible = ((JTextComponent)host).isEditable();
|
||||
} else {
|
||||
isVisible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
super.setParent(parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the Component is visible.
|
||||
*/
|
||||
public boolean isVisible() {
|
||||
return isVisible;
|
||||
}
|
||||
|
||||
/** Set to true if the component is visible. This is based off the
|
||||
* editability of the container. */
|
||||
private boolean isVisible;
|
||||
} // End of EditableView
|
||||
92
jdkSrc/jdk8/javax/swing/text/html/FormSubmitEvent.java
Normal file
92
jdkSrc/jdk8/javax/swing/text/html/FormSubmitEvent.java
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import javax.swing.text.*;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* FormSubmitEvent is used to notify interested
|
||||
* parties that a form was submitted.
|
||||
*
|
||||
* @since 1.5
|
||||
* @author Denis Sharypov
|
||||
*/
|
||||
|
||||
public class FormSubmitEvent extends HTMLFrameHyperlinkEvent {
|
||||
|
||||
/**
|
||||
* Represents an HTML form method type.
|
||||
* <UL>
|
||||
* <LI><code>GET</code> corresponds to the GET form method</LI>
|
||||
* <LI><code>POST</code> corresponds to the POST from method</LI>
|
||||
* </UL>
|
||||
* @since 1.5
|
||||
*/
|
||||
public enum MethodType { GET, POST };
|
||||
|
||||
/**
|
||||
* Creates a new object representing an html form submit event.
|
||||
*
|
||||
* @param source the object responsible for the event
|
||||
* @param type the event type
|
||||
* @param actionURL the form action URL
|
||||
* @param sourceElement the element that corresponds to the source
|
||||
* of the event
|
||||
* @param targetFrame the Frame to display the document in
|
||||
* @param method the form method type
|
||||
* @param data the form submission data
|
||||
*/
|
||||
FormSubmitEvent(Object source, EventType type, URL targetURL,
|
||||
Element sourceElement, String targetFrame,
|
||||
MethodType method, String data) {
|
||||
super(source, type, targetURL, sourceElement, targetFrame);
|
||||
this.method = method;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the form method type.
|
||||
*
|
||||
* @return the form method type, either
|
||||
* <code>Method.GET</code> or <code>Method.POST</code>.
|
||||
*/
|
||||
public MethodType getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the form submission data.
|
||||
*
|
||||
* @return the string representing the form submission data.
|
||||
*/
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
private MethodType method;
|
||||
private String data;
|
||||
}
|
||||
970
jdkSrc/jdk8/javax/swing/text/html/FormView.java
Normal file
970
jdkSrc/jdk8/javax/swing/text/html/FormView.java
Normal file
@@ -0,0 +1,970 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.text.*;
|
||||
|
||||
/**
|
||||
* Component decorator that implements the view interface
|
||||
* for form elements, <input>, <textarea>,
|
||||
* and <select>. The model for the component is stored
|
||||
* as an attribute of the the element (using StyleConstants.ModelAttribute),
|
||||
* and is used to build the component of the view. The type
|
||||
* of the model is assumed to of the type that would be set by
|
||||
* <code>HTMLDocument.HTMLReader.FormAction</code>. If there are
|
||||
* multiple views mapped over the document, they will share the
|
||||
* embedded component models.
|
||||
* <p>
|
||||
* The following table shows what components get built
|
||||
* by this view.
|
||||
* <table summary="shows what components get built by this view">
|
||||
* <tr>
|
||||
* <th>Element Type</th>
|
||||
* <th>Component built</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>input, type button</td>
|
||||
* <td>JButton</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>input, type checkbox</td>
|
||||
* <td>JCheckBox</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>input, type image</td>
|
||||
* <td>JButton</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>input, type password</td>
|
||||
* <td>JPasswordField</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>input, type radio</td>
|
||||
* <td>JRadioButton</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>input, type reset</td>
|
||||
* <td>JButton</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>input, type submit</td>
|
||||
* <td>JButton</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>input, type text</td>
|
||||
* <td>JTextField</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>select, size > 1 or multiple attribute defined</td>
|
||||
* <td>JList in a JScrollPane</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>select, size unspecified or 1</td>
|
||||
* <td>JComboBox</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>textarea</td>
|
||||
* <td>JTextArea in a JScrollPane</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>input, type file</td>
|
||||
* <td>JTextField</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* @author Timothy Prinzing
|
||||
* @author Sunita Mani
|
||||
*/
|
||||
public class FormView extends ComponentView implements ActionListener {
|
||||
|
||||
/**
|
||||
* If a value attribute is not specified for a FORM input element
|
||||
* of type "submit", then this default string is used.
|
||||
*
|
||||
* @deprecated As of 1.3, value now comes from UIManager property
|
||||
* FormView.submitButtonText
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String SUBMIT = new String("Submit Query");
|
||||
/**
|
||||
* If a value attribute is not specified for a FORM input element
|
||||
* of type "reset", then this default string is used.
|
||||
*
|
||||
* @deprecated As of 1.3, value comes from UIManager UIManager property
|
||||
* FormView.resetButtonText
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String RESET = new String("Reset");
|
||||
|
||||
/**
|
||||
* Document attribute name for storing POST data. JEditorPane.getPostData()
|
||||
* uses the same name, should be kept in sync.
|
||||
*/
|
||||
final static String PostDataProperty = "javax.swing.JEditorPane.postdata";
|
||||
|
||||
/**
|
||||
* Used to indicate if the maximum span should be the same as the
|
||||
* preferred span. This is used so that the Component's size doesn't
|
||||
* change if there is extra room on a line. The first bit is used for
|
||||
* the X direction, and the second for the y direction.
|
||||
*/
|
||||
private short maxIsPreferred;
|
||||
|
||||
/**
|
||||
* Creates a new FormView object.
|
||||
*
|
||||
* @param elem the element to decorate
|
||||
*/
|
||||
public FormView(Element elem) {
|
||||
super(elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the component. This is basically a
|
||||
* big switch statement based upon the tag type
|
||||
* and html attributes of the associated element.
|
||||
*/
|
||||
protected Component createComponent() {
|
||||
AttributeSet attr = getElement().getAttributes();
|
||||
HTML.Tag t = (HTML.Tag)
|
||||
attr.getAttribute(StyleConstants.NameAttribute);
|
||||
JComponent c = null;
|
||||
Object model = attr.getAttribute(StyleConstants.ModelAttribute);
|
||||
|
||||
// Remove listeners previously registered in shared model
|
||||
// when a new UI component is replaced. See bug 7189299.
|
||||
removeStaleListenerForModel(model);
|
||||
if (t == HTML.Tag.INPUT) {
|
||||
c = createInputComponent(attr, model);
|
||||
} else if (t == HTML.Tag.SELECT) {
|
||||
|
||||
if (model instanceof OptionListModel) {
|
||||
|
||||
JList list = new JList((ListModel) model);
|
||||
int size = HTML.getIntegerAttributeValue(attr,
|
||||
HTML.Attribute.SIZE,
|
||||
1);
|
||||
list.setVisibleRowCount(size);
|
||||
list.setSelectionModel((ListSelectionModel)model);
|
||||
c = new JScrollPane(list);
|
||||
} else {
|
||||
c = new JComboBox((ComboBoxModel) model);
|
||||
maxIsPreferred = 3;
|
||||
}
|
||||
} else if (t == HTML.Tag.TEXTAREA) {
|
||||
JTextArea area = new JTextArea((Document) model);
|
||||
int rows = HTML.getIntegerAttributeValue(attr,
|
||||
HTML.Attribute.ROWS,
|
||||
1);
|
||||
area.setRows(rows);
|
||||
int cols = HTML.getIntegerAttributeValue(attr,
|
||||
HTML.Attribute.COLS,
|
||||
20);
|
||||
maxIsPreferred = 3;
|
||||
area.setColumns(cols);
|
||||
c = new JScrollPane(area,
|
||||
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
|
||||
}
|
||||
|
||||
if (c != null) {
|
||||
c.setAlignmentY(1.0f);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a component for an <INPUT> element based on the
|
||||
* value of the "type" attribute.
|
||||
*
|
||||
* @param set of attributes associated with the <INPUT> element.
|
||||
* @param model the value of the StyleConstants.ModelAttribute
|
||||
* @return the component.
|
||||
*/
|
||||
private JComponent createInputComponent(AttributeSet attr, Object model) {
|
||||
JComponent c = null;
|
||||
String type = (String) attr.getAttribute(HTML.Attribute.TYPE);
|
||||
|
||||
if (type.equals("submit") || type.equals("reset")) {
|
||||
String value = (String)
|
||||
attr.getAttribute(HTML.Attribute.VALUE);
|
||||
if (value == null) {
|
||||
if (type.equals("submit")) {
|
||||
value = UIManager.getString("FormView.submitButtonText");
|
||||
} else {
|
||||
value = UIManager.getString("FormView.resetButtonText");
|
||||
}
|
||||
}
|
||||
JButton button = new JButton(value);
|
||||
if (model != null) {
|
||||
button.setModel((ButtonModel)model);
|
||||
button.addActionListener(this);
|
||||
}
|
||||
c = button;
|
||||
maxIsPreferred = 3;
|
||||
} else if (type.equals("image")) {
|
||||
String srcAtt = (String) attr.getAttribute(HTML.Attribute.SRC);
|
||||
JButton button;
|
||||
try {
|
||||
URL base = ((HTMLDocument)getElement().getDocument()).getBase();
|
||||
URL srcURL = new URL(base, srcAtt);
|
||||
Icon icon = new ImageIcon(srcURL);
|
||||
button = new JButton(icon);
|
||||
} catch (MalformedURLException e) {
|
||||
button = new JButton(srcAtt);
|
||||
}
|
||||
if (model != null) {
|
||||
button.setModel((ButtonModel)model);
|
||||
button.addMouseListener(new MouseEventListener());
|
||||
}
|
||||
c = button;
|
||||
maxIsPreferred = 3;
|
||||
} else if (type.equals("checkbox")) {
|
||||
c = new JCheckBox();
|
||||
if (model != null) {
|
||||
((JCheckBox)c).setModel((JToggleButton.ToggleButtonModel) model);
|
||||
}
|
||||
maxIsPreferred = 3;
|
||||
} else if (type.equals("radio")) {
|
||||
c = new JRadioButton();
|
||||
if (model != null) {
|
||||
((JRadioButton)c).setModel((JToggleButton.ToggleButtonModel)model);
|
||||
}
|
||||
maxIsPreferred = 3;
|
||||
} else if (type.equals("text")) {
|
||||
int size = HTML.getIntegerAttributeValue(attr,
|
||||
HTML.Attribute.SIZE,
|
||||
-1);
|
||||
JTextField field;
|
||||
if (size > 0) {
|
||||
field = new JTextField();
|
||||
field.setColumns(size);
|
||||
}
|
||||
else {
|
||||
field = new JTextField();
|
||||
field.setColumns(20);
|
||||
}
|
||||
c = field;
|
||||
if (model != null) {
|
||||
field.setDocument((Document) model);
|
||||
}
|
||||
field.addActionListener(this);
|
||||
maxIsPreferred = 3;
|
||||
} else if (type.equals("password")) {
|
||||
JPasswordField field = new JPasswordField();
|
||||
c = field;
|
||||
if (model != null) {
|
||||
field.setDocument((Document) model);
|
||||
}
|
||||
int size = HTML.getIntegerAttributeValue(attr,
|
||||
HTML.Attribute.SIZE,
|
||||
-1);
|
||||
field.setColumns((size > 0) ? size : 20);
|
||||
field.addActionListener(this);
|
||||
maxIsPreferred = 3;
|
||||
} else if (type.equals("file")) {
|
||||
JTextField field = new JTextField();
|
||||
if (model != null) {
|
||||
field.setDocument((Document)model);
|
||||
}
|
||||
int size = HTML.getIntegerAttributeValue(attr, HTML.Attribute.SIZE,
|
||||
-1);
|
||||
field.setColumns((size > 0) ? size : 20);
|
||||
JButton browseButton = new JButton(UIManager.getString
|
||||
("FormView.browseFileButtonText"));
|
||||
Box box = Box.createHorizontalBox();
|
||||
box.add(field);
|
||||
box.add(Box.createHorizontalStrut(5));
|
||||
box.add(browseButton);
|
||||
browseButton.addActionListener(new BrowseFileAction(
|
||||
attr, (Document)model));
|
||||
c = box;
|
||||
maxIsPreferred = 3;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
private void removeStaleListenerForModel(Object model) {
|
||||
if (model instanceof DefaultButtonModel) {
|
||||
// case of JButton whose model is DefaultButtonModel
|
||||
// Need to remove stale ActionListener, ChangeListener and
|
||||
// ItemListener that are instance of AbstractButton$Handler.
|
||||
DefaultButtonModel buttonModel = (DefaultButtonModel) model;
|
||||
String listenerClass = "javax.swing.AbstractButton$Handler";
|
||||
for (ActionListener listener : buttonModel.getActionListeners()) {
|
||||
if (listenerClass.equals(listener.getClass().getName())) {
|
||||
buttonModel.removeActionListener(listener);
|
||||
}
|
||||
}
|
||||
for (ChangeListener listener : buttonModel.getChangeListeners()) {
|
||||
if (listenerClass.equals(listener.getClass().getName())) {
|
||||
buttonModel.removeChangeListener(listener);
|
||||
}
|
||||
}
|
||||
for (ItemListener listener : buttonModel.getItemListeners()) {
|
||||
if (listenerClass.equals(listener.getClass().getName())) {
|
||||
buttonModel.removeItemListener(listener);
|
||||
}
|
||||
}
|
||||
} else if (model instanceof AbstractListModel) {
|
||||
// case of JComboBox and JList
|
||||
// For JList, the stale ListDataListener is instance
|
||||
// BasicListUI$Handler.
|
||||
// For JComboBox, there are 2 stale ListDataListeners, which are
|
||||
// BasicListUI$Handler and BasicComboBoxUI$Handler.
|
||||
AbstractListModel listModel = (AbstractListModel) model;
|
||||
String listenerClass1 =
|
||||
"javax.swing.plaf.basic.BasicListUI$Handler";
|
||||
String listenerClass2 =
|
||||
"javax.swing.plaf.basic.BasicComboBoxUI$Handler";
|
||||
for (ListDataListener listener : listModel.getListDataListeners()) {
|
||||
if (listenerClass1.equals(listener.getClass().getName())
|
||||
|| listenerClass2.equals(listener.getClass().getName()))
|
||||
{
|
||||
listModel.removeListDataListener(listener);
|
||||
}
|
||||
}
|
||||
} else if (model instanceof AbstractDocument) {
|
||||
// case of JPasswordField, JTextField and JTextArea
|
||||
// All have 2 stale DocumentListeners.
|
||||
String listenerClass1 =
|
||||
"javax.swing.plaf.basic.BasicTextUI$UpdateHandler";
|
||||
String listenerClass2 =
|
||||
"javax.swing.text.DefaultCaret$Handler";
|
||||
AbstractDocument docModel = (AbstractDocument) model;
|
||||
for (DocumentListener listener : docModel.getDocumentListeners()) {
|
||||
if (listenerClass1.equals(listener.getClass().getName())
|
||||
|| listenerClass2.equals(listener.getClass().getName()))
|
||||
{
|
||||
docModel.removeDocumentListener(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the maximum span for this view along an
|
||||
* axis. For certain components, the maximum and preferred span are the
|
||||
* same. For others this will return the value
|
||||
* returned by Component.getMaximumSize along the
|
||||
* axis of interest.
|
||||
*
|
||||
* @param axis may be either View.X_AXIS or View.Y_AXIS
|
||||
* @return the span the view would like to be rendered into >= 0.
|
||||
* Typically the view is told to render into the span
|
||||
* that is returned, although there is no guarantee.
|
||||
* The parent may choose to resize or break the view.
|
||||
* @exception IllegalArgumentException for an invalid axis
|
||||
*/
|
||||
public float getMaximumSpan(int axis) {
|
||||
switch (axis) {
|
||||
case View.X_AXIS:
|
||||
if ((maxIsPreferred & 1) == 1) {
|
||||
super.getMaximumSpan(axis);
|
||||
return getPreferredSpan(axis);
|
||||
}
|
||||
return super.getMaximumSpan(axis);
|
||||
case View.Y_AXIS:
|
||||
if ((maxIsPreferred & 2) == 2) {
|
||||
super.getMaximumSpan(axis);
|
||||
return getPreferredSpan(axis);
|
||||
}
|
||||
return super.getMaximumSpan(axis);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return super.getMaximumSpan(axis);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Responsible for processing the ActionEvent.
|
||||
* If the element associated with the FormView,
|
||||
* has a type of "submit", "reset", "text" or "password"
|
||||
* then the action is processed. In the case of a "submit"
|
||||
* the form is submitted. In the case of a "reset"
|
||||
* the form is reset to its original state.
|
||||
* In the case of "text" or "password", if the
|
||||
* element is the last one of type "text" or "password",
|
||||
* the form is submitted. Otherwise, focus is transferred
|
||||
* to the next component in the form.
|
||||
*
|
||||
* @param evt the ActionEvent.
|
||||
*/
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
Element element = getElement();
|
||||
StringBuilder dataBuffer = new StringBuilder();
|
||||
HTMLDocument doc = (HTMLDocument)getDocument();
|
||||
AttributeSet attr = element.getAttributes();
|
||||
|
||||
String type = (String) attr.getAttribute(HTML.Attribute.TYPE);
|
||||
|
||||
if (type.equals("submit")) {
|
||||
getFormData(dataBuffer);
|
||||
submitData(dataBuffer.toString());
|
||||
} else if (type.equals("reset")) {
|
||||
resetForm();
|
||||
} else if (type.equals("text") || type.equals("password")) {
|
||||
if (isLastTextOrPasswordField()) {
|
||||
getFormData(dataBuffer);
|
||||
submitData(dataBuffer.toString());
|
||||
} else {
|
||||
getComponent().transferFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is responsible for submitting the form data.
|
||||
* A thread is forked to undertake the submission.
|
||||
*/
|
||||
protected void submitData(String data) {
|
||||
Element form = getFormElement();
|
||||
AttributeSet attrs = form.getAttributes();
|
||||
HTMLDocument doc = (HTMLDocument) form.getDocument();
|
||||
URL base = doc.getBase();
|
||||
|
||||
String target = (String) attrs.getAttribute(HTML.Attribute.TARGET);
|
||||
if (target == null) {
|
||||
target = "_self";
|
||||
}
|
||||
|
||||
String method = (String) attrs.getAttribute(HTML.Attribute.METHOD);
|
||||
if (method == null) {
|
||||
method = "GET";
|
||||
}
|
||||
method = method.toLowerCase();
|
||||
boolean isPostMethod = method.equals("post");
|
||||
if (isPostMethod) {
|
||||
storePostData(doc, target, data);
|
||||
}
|
||||
|
||||
String action = (String) attrs.getAttribute(HTML.Attribute.ACTION);
|
||||
URL actionURL;
|
||||
try {
|
||||
actionURL = (action == null)
|
||||
? new URL(base.getProtocol(), base.getHost(),
|
||||
base.getPort(), base.getFile())
|
||||
: new URL(base, action);
|
||||
if (!isPostMethod) {
|
||||
String query = data.toString();
|
||||
actionURL = new URL(actionURL + "?" + query);
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
actionURL = null;
|
||||
}
|
||||
final JEditorPane c = (JEditorPane) getContainer();
|
||||
HTMLEditorKit kit = (HTMLEditorKit) c.getEditorKit();
|
||||
|
||||
FormSubmitEvent formEvent = null;
|
||||
if (!kit.isAutoFormSubmission() || doc.isFrameDocument()) {
|
||||
FormSubmitEvent.MethodType methodType = isPostMethod
|
||||
? FormSubmitEvent.MethodType.POST
|
||||
: FormSubmitEvent.MethodType.GET;
|
||||
formEvent = new FormSubmitEvent(
|
||||
FormView.this, HyperlinkEvent.EventType.ACTIVATED,
|
||||
actionURL, form, target, methodType, data);
|
||||
|
||||
}
|
||||
// setPage() may take significant time so schedule it to run later.
|
||||
final FormSubmitEvent fse = formEvent;
|
||||
final URL url = actionURL;
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
if (fse != null) {
|
||||
c.fireHyperlinkUpdate(fse);
|
||||
} else {
|
||||
try {
|
||||
c.setPage(url);
|
||||
} catch (IOException e) {
|
||||
UIManager.getLookAndFeel().provideErrorFeedback(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void storePostData(HTMLDocument doc, String target, String data) {
|
||||
|
||||
/* POST data is stored into the document property named by constant
|
||||
* PostDataProperty from where it is later retrieved by method
|
||||
* JEditorPane.getPostData(). If the current document is in a frame,
|
||||
* the data is initially put into the toplevel (frameset) document
|
||||
* property (named <PostDataProperty>.<Target frame name>). It is the
|
||||
* responsibility of FrameView which updates the target frame
|
||||
* to move data from the frameset document property into the frame
|
||||
* document property.
|
||||
*/
|
||||
|
||||
Document propDoc = doc;
|
||||
String propName = PostDataProperty;
|
||||
|
||||
if (doc.isFrameDocument()) {
|
||||
// find the top-most JEditorPane holding the frameset view.
|
||||
FrameView.FrameEditorPane p =
|
||||
(FrameView.FrameEditorPane) getContainer();
|
||||
FrameView v = p.getFrameView();
|
||||
JEditorPane c = v.getOutermostJEditorPane();
|
||||
if (c != null) {
|
||||
propDoc = c.getDocument();
|
||||
propName += ("." + target);
|
||||
}
|
||||
}
|
||||
|
||||
propDoc.putProperty(propName, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* MouseEventListener class to handle form submissions when
|
||||
* an input with type equal to image is clicked on.
|
||||
* A MouseListener is necessary since along with the image
|
||||
* data the coordinates associated with the mouse click
|
||||
* need to be submitted.
|
||||
*/
|
||||
protected class MouseEventListener extends MouseAdapter {
|
||||
|
||||
public void mouseReleased(MouseEvent evt) {
|
||||
String imageData = getImageData(evt.getPoint());
|
||||
imageSubmit(imageData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called to submit a form in response
|
||||
* to a click on an image -- an <INPUT> form
|
||||
* element of type "image".
|
||||
*
|
||||
* @param imageData the mouse click coordinates.
|
||||
*/
|
||||
protected void imageSubmit(String imageData) {
|
||||
|
||||
StringBuilder dataBuffer = new StringBuilder();
|
||||
Element elem = getElement();
|
||||
HTMLDocument hdoc = (HTMLDocument)elem.getDocument();
|
||||
getFormData(dataBuffer);
|
||||
if (dataBuffer.length() > 0) {
|
||||
dataBuffer.append('&');
|
||||
}
|
||||
dataBuffer.append(imageData);
|
||||
submitData(dataBuffer.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the value of the name attribute
|
||||
* associated with the input element of type
|
||||
* image. If name is defined it is encoded using
|
||||
* the URLEncoder.encode() method and the
|
||||
* image data is returned in the following format:
|
||||
* name + ".x" +"="+ x +"&"+ name +".y"+"="+ y
|
||||
* otherwise,
|
||||
* "x="+ x +"&y="+ y
|
||||
*
|
||||
* @param point associated with the mouse click.
|
||||
* @return the image data.
|
||||
*/
|
||||
private String getImageData(Point point) {
|
||||
|
||||
String mouseCoords = point.x + ":" + point.y;
|
||||
int sep = mouseCoords.indexOf(':');
|
||||
String x = mouseCoords.substring(0, sep);
|
||||
String y = mouseCoords.substring(++sep);
|
||||
String name = (String) getElement().getAttributes().getAttribute(HTML.Attribute.NAME);
|
||||
|
||||
String data;
|
||||
if (name == null || name.equals("")) {
|
||||
data = "x="+ x +"&y="+ y;
|
||||
} else {
|
||||
name = URLEncoder.encode(name);
|
||||
data = name + ".x" +"="+ x +"&"+ name +".y"+"="+ y;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The following methods provide functionality required to
|
||||
* iterate over a the elements of the form and in the case
|
||||
* of a form submission, extract the data from each model
|
||||
* that is associated with each form element, and in the
|
||||
* case of reset, reinitialize the each model to its
|
||||
* initial state.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Returns the Element representing the <code>FORM</code>.
|
||||
*/
|
||||
private Element getFormElement() {
|
||||
Element elem = getElement();
|
||||
while (elem != null) {
|
||||
if (elem.getAttributes().getAttribute
|
||||
(StyleConstants.NameAttribute) == HTML.Tag.FORM) {
|
||||
return elem;
|
||||
}
|
||||
elem = elem.getParentElement();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the
|
||||
* element hierarchy, extracting data from the
|
||||
* models associated with the relevant form elements.
|
||||
* "Relevant" means the form elements that are part
|
||||
* of the same form whose element triggered the submit
|
||||
* action.
|
||||
*
|
||||
* @param buffer the buffer that contains that data to submit
|
||||
* @param targetElement the element that triggered the
|
||||
* form submission
|
||||
*/
|
||||
private void getFormData(StringBuilder buffer) {
|
||||
Element formE = getFormElement();
|
||||
if (formE != null) {
|
||||
ElementIterator it = new ElementIterator(formE);
|
||||
Element next;
|
||||
|
||||
while ((next = it.next()) != null) {
|
||||
if (isControl(next)) {
|
||||
String type = (String)next.getAttributes().getAttribute
|
||||
(HTML.Attribute.TYPE);
|
||||
|
||||
if (type != null && type.equals("submit") &&
|
||||
next != getElement()) {
|
||||
// do nothing - this submit is not the trigger
|
||||
} else if (type == null || !type.equals("image")) {
|
||||
// images only result in data if they triggered
|
||||
// the submit and they require that the mouse click
|
||||
// coords be appended to the data. Hence its
|
||||
// processing is handled by the view.
|
||||
loadElementDataIntoBuffer(next, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the data
|
||||
* associated with the element into the buffer.
|
||||
* The format in which data is appended depends
|
||||
* on the type of the form element. Essentially
|
||||
* data is loaded in name/value pairs.
|
||||
*
|
||||
*/
|
||||
private void loadElementDataIntoBuffer(Element elem, StringBuilder buffer) {
|
||||
|
||||
AttributeSet attr = elem.getAttributes();
|
||||
String name = (String)attr.getAttribute(HTML.Attribute.NAME);
|
||||
if (name == null) {
|
||||
return;
|
||||
}
|
||||
String value = null;
|
||||
HTML.Tag tag = (HTML.Tag)elem.getAttributes().getAttribute
|
||||
(StyleConstants.NameAttribute);
|
||||
|
||||
if (tag == HTML.Tag.INPUT) {
|
||||
value = getInputElementData(attr);
|
||||
} else if (tag == HTML.Tag.TEXTAREA) {
|
||||
value = getTextAreaData(attr);
|
||||
} else if (tag == HTML.Tag.SELECT) {
|
||||
loadSelectData(attr, buffer);
|
||||
}
|
||||
|
||||
if (name != null && value != null) {
|
||||
appendBuffer(buffer, name, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the data associated with an <INPUT> form
|
||||
* element. The value of "type" attributes is
|
||||
* used to determine the type of the model associated
|
||||
* with the element and then the relevant data is
|
||||
* extracted.
|
||||
*/
|
||||
private String getInputElementData(AttributeSet attr) {
|
||||
|
||||
Object model = attr.getAttribute(StyleConstants.ModelAttribute);
|
||||
String type = (String) attr.getAttribute(HTML.Attribute.TYPE);
|
||||
String value = null;
|
||||
|
||||
if (type.equals("text") || type.equals("password")) {
|
||||
Document doc = (Document)model;
|
||||
try {
|
||||
value = doc.getText(0, doc.getLength());
|
||||
} catch (BadLocationException e) {
|
||||
value = null;
|
||||
}
|
||||
} else if (type.equals("submit") || type.equals("hidden")) {
|
||||
value = (String) attr.getAttribute(HTML.Attribute.VALUE);
|
||||
if (value == null) {
|
||||
value = "";
|
||||
}
|
||||
} else if (type.equals("radio") || type.equals("checkbox")) {
|
||||
ButtonModel m = (ButtonModel)model;
|
||||
if (m.isSelected()) {
|
||||
value = (String) attr.getAttribute(HTML.Attribute.VALUE);
|
||||
if (value == null) {
|
||||
value = "on";
|
||||
}
|
||||
}
|
||||
} else if (type.equals("file")) {
|
||||
Document doc = (Document)model;
|
||||
String path;
|
||||
|
||||
try {
|
||||
path = doc.getText(0, doc.getLength());
|
||||
} catch (BadLocationException e) {
|
||||
path = null;
|
||||
}
|
||||
if (path != null && path.length() > 0) {
|
||||
value = path;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data associated with the <TEXTAREA> form
|
||||
* element. This is done by getting the text stored in the
|
||||
* Document model.
|
||||
*/
|
||||
private String getTextAreaData(AttributeSet attr) {
|
||||
Document doc = (Document)attr.getAttribute(StyleConstants.ModelAttribute);
|
||||
try {
|
||||
return doc.getText(0, doc.getLength());
|
||||
} catch (BadLocationException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loads the buffer with the data associated with the Select
|
||||
* form element. Basically, only items that are selected
|
||||
* and have their name attribute set are added to the buffer.
|
||||
*/
|
||||
private void loadSelectData(AttributeSet attr, StringBuilder buffer) {
|
||||
|
||||
String name = (String)attr.getAttribute(HTML.Attribute.NAME);
|
||||
if (name == null) {
|
||||
return;
|
||||
}
|
||||
Object m = attr.getAttribute(StyleConstants.ModelAttribute);
|
||||
if (m instanceof OptionListModel) {
|
||||
OptionListModel<Option> model = (OptionListModel<Option>) m;
|
||||
|
||||
for (int i = 0; i < model.getSize(); i++) {
|
||||
if (model.isSelectedIndex(i)) {
|
||||
Option option = model.getElementAt(i);
|
||||
appendBuffer(buffer, name, option.getValue());
|
||||
}
|
||||
}
|
||||
} else if (m instanceof ComboBoxModel) {
|
||||
ComboBoxModel model = (ComboBoxModel)m;
|
||||
Option option = (Option)model.getSelectedItem();
|
||||
if (option != null) {
|
||||
appendBuffer(buffer, name, option.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends name / value pairs into the
|
||||
* buffer. Both names and values are encoded using the
|
||||
* URLEncoder.encode() method before being added to the
|
||||
* buffer.
|
||||
*/
|
||||
private void appendBuffer(StringBuilder buffer, String name, String value) {
|
||||
if (buffer.length() > 0) {
|
||||
buffer.append('&');
|
||||
}
|
||||
String encodedName = URLEncoder.encode(name);
|
||||
buffer.append(encodedName);
|
||||
buffer.append('=');
|
||||
String encodedValue = URLEncoder.encode(value);
|
||||
buffer.append(encodedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the Element <code>elem</code> represents a control.
|
||||
*/
|
||||
private boolean isControl(Element elem) {
|
||||
return elem.isLeaf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the element hierarchy to determine if
|
||||
* the element parameter, which is assumed to be an
|
||||
* <INPUT> element of type password or text, is the last
|
||||
* one of either kind, in the form to which it belongs.
|
||||
*/
|
||||
boolean isLastTextOrPasswordField() {
|
||||
Element parent = getFormElement();
|
||||
Element elem = getElement();
|
||||
|
||||
if (parent != null) {
|
||||
ElementIterator it = new ElementIterator(parent);
|
||||
Element next;
|
||||
boolean found = false;
|
||||
|
||||
while ((next = it.next()) != null) {
|
||||
if (next == elem) {
|
||||
found = true;
|
||||
}
|
||||
else if (found && isControl(next)) {
|
||||
AttributeSet elemAttr = next.getAttributes();
|
||||
|
||||
if (HTMLDocument.matchNameAttribute
|
||||
(elemAttr, HTML.Tag.INPUT)) {
|
||||
String type = (String)elemAttr.getAttribute
|
||||
(HTML.Attribute.TYPE);
|
||||
|
||||
if ("text".equals(type) || "password".equals(type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the form
|
||||
* to its initial state by reinitializing the models
|
||||
* associated with each form element to their initial
|
||||
* values.
|
||||
*
|
||||
* param elem the element that triggered the reset
|
||||
*/
|
||||
void resetForm() {
|
||||
Element parent = getFormElement();
|
||||
|
||||
if (parent != null) {
|
||||
ElementIterator it = new ElementIterator(parent);
|
||||
Element next;
|
||||
|
||||
while((next = it.next()) != null) {
|
||||
if (isControl(next)) {
|
||||
AttributeSet elemAttr = next.getAttributes();
|
||||
Object m = elemAttr.getAttribute(StyleConstants.
|
||||
ModelAttribute);
|
||||
if (m instanceof TextAreaDocument) {
|
||||
TextAreaDocument doc = (TextAreaDocument)m;
|
||||
doc.reset();
|
||||
} else if (m instanceof PlainDocument) {
|
||||
try {
|
||||
PlainDocument doc = (PlainDocument)m;
|
||||
doc.remove(0, doc.getLength());
|
||||
if (HTMLDocument.matchNameAttribute
|
||||
(elemAttr, HTML.Tag.INPUT)) {
|
||||
String value = (String)elemAttr.
|
||||
getAttribute(HTML.Attribute.VALUE);
|
||||
if (value != null) {
|
||||
doc.insertString(0, value, null);
|
||||
}
|
||||
}
|
||||
} catch (BadLocationException e) {
|
||||
}
|
||||
} else if (m instanceof OptionListModel) {
|
||||
OptionListModel model = (OptionListModel) m;
|
||||
int size = model.getSize();
|
||||
for (int i = 0; i < size; i++) {
|
||||
model.removeIndexInterval(i, i);
|
||||
}
|
||||
BitSet selectionRange = model.getInitialSelection();
|
||||
for (int i = 0; i < selectionRange.size(); i++) {
|
||||
if (selectionRange.get(i)) {
|
||||
model.addSelectionInterval(i, i);
|
||||
}
|
||||
}
|
||||
} else if (m instanceof OptionComboBoxModel) {
|
||||
OptionComboBoxModel model = (OptionComboBoxModel) m;
|
||||
Option option = model.getInitialSelection();
|
||||
if (option != null) {
|
||||
model.setSelectedItem(option);
|
||||
}
|
||||
} else if (m instanceof JToggleButton.ToggleButtonModel) {
|
||||
boolean checked = ((String)elemAttr.getAttribute
|
||||
(HTML.Attribute.CHECKED) != null);
|
||||
JToggleButton.ToggleButtonModel model =
|
||||
(JToggleButton.ToggleButtonModel)m;
|
||||
model.setSelected(checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* BrowseFileAction is used for input type == file. When the user
|
||||
* clicks the button a JFileChooser is brought up allowing the user
|
||||
* to select a file in the file system. The resulting path to the selected
|
||||
* file is set in the text field (actually an instance of Document).
|
||||
*/
|
||||
private class BrowseFileAction implements ActionListener {
|
||||
private AttributeSet attrs;
|
||||
private Document model;
|
||||
|
||||
BrowseFileAction(AttributeSet attrs, Document model) {
|
||||
this.attrs = attrs;
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent ae) {
|
||||
// PENDING: When mime support is added to JFileChooser use the
|
||||
// accept value of attrs.
|
||||
JFileChooser fc = new JFileChooser();
|
||||
fc.setMultiSelectionEnabled(false);
|
||||
if (fc.showOpenDialog(getContainer()) ==
|
||||
JFileChooser.APPROVE_OPTION) {
|
||||
File selected = fc.getSelectedFile();
|
||||
|
||||
if (selected != null) {
|
||||
try {
|
||||
if (model.getLength() > 0) {
|
||||
model.remove(0, model.getLength());
|
||||
}
|
||||
model.insertString(0, selected.getPath(), null);
|
||||
} catch (BadLocationException ble) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
322
jdkSrc/jdk8/javax/swing/text/html/FrameSetView.java
Normal file
322
jdkSrc/jdk8/javax/swing/text/html/FrameSetView.java
Normal file
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.event.*;
|
||||
|
||||
/**
|
||||
* Implements a FrameSetView, intended to support the HTML
|
||||
* <FRAMESET> tag. Supports the ROWS and COLS attributes.
|
||||
*
|
||||
* @author Sunita Mani
|
||||
*
|
||||
* Credit also to the hotjava browser engineers that
|
||||
* worked on making the allocation of space algorithms
|
||||
* conform to the HTML 4.0 standard and also be netscape
|
||||
* compatible.
|
||||
*
|
||||
*/
|
||||
|
||||
class FrameSetView extends javax.swing.text.BoxView {
|
||||
|
||||
String[] children;
|
||||
int[] percentChildren;
|
||||
int[] absoluteChildren;
|
||||
int[] relativeChildren;
|
||||
int percentTotals;
|
||||
int absoluteTotals;
|
||||
int relativeTotals;
|
||||
|
||||
/**
|
||||
* Constructs a FrameSetView for the given element.
|
||||
*
|
||||
* @param elem the element that this view is responsible for
|
||||
*/
|
||||
public FrameSetView(Element elem, int axis) {
|
||||
super(elem, axis);
|
||||
children = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the ROW or COL attributes and returns
|
||||
* an array of strings that represent the space
|
||||
* distribution.
|
||||
*
|
||||
*/
|
||||
private String[] parseRowColSpec(HTML.Attribute key) {
|
||||
|
||||
AttributeSet attributes = getElement().getAttributes();
|
||||
String spec = "*";
|
||||
if (attributes != null) {
|
||||
if (attributes.getAttribute(key) != null) {
|
||||
spec = (String)attributes.getAttribute(key);
|
||||
}
|
||||
}
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(spec, ",");
|
||||
int nTokens = tokenizer.countTokens();
|
||||
int n = getViewCount();
|
||||
String[] items = new String[Math.max(nTokens, n)];
|
||||
int i = 0;
|
||||
for (; i < nTokens; i++) {
|
||||
items[i] = tokenizer.nextToken().trim();
|
||||
// As per the spec, 100% is the same as *
|
||||
// hence the mapping.
|
||||
//
|
||||
if (items[i].equals("100%")) {
|
||||
items[i] = "*";
|
||||
}
|
||||
}
|
||||
// extend spec if we have more children than specified
|
||||
// in ROWS or COLS attribute
|
||||
for (; i < items.length; i++) {
|
||||
items[i] = "*";
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes a number of internal state variables
|
||||
* that store information about space allocation
|
||||
* for the frames contained within the frameset.
|
||||
*/
|
||||
private void init() {
|
||||
if (getAxis() == View.Y_AXIS) {
|
||||
children = parseRowColSpec(HTML.Attribute.ROWS);
|
||||
} else {
|
||||
children = parseRowColSpec(HTML.Attribute.COLS);
|
||||
}
|
||||
percentChildren = new int[children.length];
|
||||
relativeChildren = new int[children.length];
|
||||
absoluteChildren = new int[children.length];
|
||||
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
percentChildren[i] = -1;
|
||||
relativeChildren[i] = -1;
|
||||
absoluteChildren[i] = -1;
|
||||
|
||||
if (children[i].endsWith("*")) {
|
||||
if (children[i].length() > 1) {
|
||||
relativeChildren[i] =
|
||||
Integer.parseInt(children[i].substring(
|
||||
0, children[i].length()-1));
|
||||
relativeTotals += relativeChildren[i];
|
||||
} else {
|
||||
relativeChildren[i] = 1;
|
||||
relativeTotals += 1;
|
||||
}
|
||||
} else if (children[i].indexOf('%') != -1) {
|
||||
percentChildren[i] = parseDigits(children[i]);
|
||||
percentTotals += percentChildren[i];
|
||||
} else {
|
||||
absoluteChildren[i] = Integer.parseInt(children[i]);
|
||||
}
|
||||
}
|
||||
if (percentTotals > 100) {
|
||||
for (int i = 0; i < percentChildren.length; i++) {
|
||||
if (percentChildren[i] > 0) {
|
||||
percentChildren[i] =
|
||||
(percentChildren[i] * 100) / percentTotals;
|
||||
}
|
||||
}
|
||||
percentTotals = 100;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform layout for the major axis of the box (i.e. the
|
||||
* axis that it represents). The results of the layout should
|
||||
* be placed in the given arrays which represent the allocations
|
||||
* to the children along the major axis.
|
||||
*
|
||||
* @param targetSpan the total span given to the view, which
|
||||
* would be used to layout the children
|
||||
* @param axis the axis being layed out
|
||||
* @param offsets the offsets from the origin of the view for
|
||||
* each of the child views; this is a return value and is
|
||||
* filled in by the implementation of this method
|
||||
* @param spans the span of each child view; this is a return
|
||||
* value and is filled in by the implementation of this method
|
||||
* @return the offset and span for each child view in the
|
||||
* offsets and spans parameters
|
||||
*/
|
||||
protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
|
||||
int[] spans) {
|
||||
if (children == null) {
|
||||
init();
|
||||
}
|
||||
SizeRequirements.calculateTiledPositions(targetSpan, null,
|
||||
getChildRequests(targetSpan,
|
||||
axis),
|
||||
offsets, spans);
|
||||
}
|
||||
|
||||
protected SizeRequirements[] getChildRequests(int targetSpan, int axis) {
|
||||
|
||||
int span[] = new int[children.length];
|
||||
|
||||
spread(targetSpan, span);
|
||||
int n = getViewCount();
|
||||
SizeRequirements[] reqs = new SizeRequirements[n];
|
||||
for (int i = 0, sIndex = 0; i < n; i++) {
|
||||
View v = getView(i);
|
||||
if ((v instanceof FrameView) || (v instanceof FrameSetView)) {
|
||||
reqs[i] = new SizeRequirements((int) v.getMinimumSpan(axis),
|
||||
span[sIndex],
|
||||
(int) v.getMaximumSpan(axis),
|
||||
0.5f);
|
||||
sIndex++;
|
||||
} else {
|
||||
int min = (int) v.getMinimumSpan(axis);
|
||||
int pref = (int) v.getPreferredSpan(axis);
|
||||
int max = (int) v.getMaximumSpan(axis);
|
||||
float a = v.getAlignment(axis);
|
||||
reqs[i] = new SizeRequirements(min, pref, max, a);
|
||||
}
|
||||
}
|
||||
return reqs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is responsible for returning in span[] the
|
||||
* span for each child view along the major axis. it
|
||||
* computes this based on the information that extracted
|
||||
* from the value of the ROW/COL attribute.
|
||||
*/
|
||||
private void spread(int targetSpan, int span[]) {
|
||||
|
||||
if (targetSpan == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int tempSpace = 0;
|
||||
int remainingSpace = targetSpan;
|
||||
|
||||
// allocate the absolute's first, they have
|
||||
// precedence
|
||||
//
|
||||
for (int i = 0; i < span.length; i++) {
|
||||
if (absoluteChildren[i] > 0) {
|
||||
span[i] = absoluteChildren[i];
|
||||
remainingSpace -= span[i];
|
||||
}
|
||||
}
|
||||
|
||||
// then deal with percents.
|
||||
//
|
||||
tempSpace = remainingSpace;
|
||||
for (int i = 0; i < span.length; i++) {
|
||||
if (percentChildren[i] > 0 && tempSpace > 0) {
|
||||
span[i] = (percentChildren[i] * tempSpace) / 100;
|
||||
remainingSpace -= span[i];
|
||||
} else if (percentChildren[i] > 0 && tempSpace <= 0) {
|
||||
span[i] = targetSpan / span.length;
|
||||
remainingSpace -= span[i];
|
||||
}
|
||||
}
|
||||
|
||||
// allocate remainingSpace to relative
|
||||
if (remainingSpace > 0 && relativeTotals > 0) {
|
||||
for (int i = 0; i < span.length; i++) {
|
||||
if (relativeChildren[i] > 0) {
|
||||
span[i] = (remainingSpace *
|
||||
relativeChildren[i]) / relativeTotals;
|
||||
}
|
||||
}
|
||||
} else if (remainingSpace > 0) {
|
||||
// There are no relative columns and the space has been
|
||||
// under- or overallocated. In this case, turn all the
|
||||
// percentage and pixel specified columns to percentage
|
||||
// columns based on the ratio of their pixel count to the
|
||||
// total "virtual" size. (In the case of percentage columns,
|
||||
// the pixel count would equal the specified percentage
|
||||
// of the screen size.
|
||||
|
||||
// This action is in accordance with the HTML
|
||||
// 4.0 spec (see section 8.3, the end of the discussion of
|
||||
// the FRAMESET tag). The precedence of percentage and pixel
|
||||
// specified columns is unclear (spec seems to indicate that
|
||||
// they share priority, however, unspecified what happens when
|
||||
// overallocation occurs.)
|
||||
|
||||
// addendum is that we behave similar to netscape in that specified
|
||||
// widths have precedance over percentage widths...
|
||||
|
||||
float vTotal = (float)(targetSpan - remainingSpace);
|
||||
float[] tempPercents = new float[span.length];
|
||||
remainingSpace = targetSpan;
|
||||
for (int i = 0; i < span.length; i++) {
|
||||
// ok we know what our total space is, and we know how large each
|
||||
// column should be relative to each other... therefore we can use
|
||||
// that relative information to deduce their percentages of a whole
|
||||
// and then scale them appropriately for the correct size
|
||||
tempPercents[i] = ((float)span[i] / vTotal) * 100.00f;
|
||||
span[i] = (int) ( ((float)targetSpan * tempPercents[i]) / 100.00f);
|
||||
remainingSpace -= span[i];
|
||||
}
|
||||
|
||||
|
||||
// this is for just in case there is something left over.. if there is we just
|
||||
// add it one pixel at a time to the frames in order.. We shouldn't really ever get
|
||||
// here and if we do it shouldn't be with more than 1 pixel, maybe two.
|
||||
int i = 0;
|
||||
while (remainingSpace != 0) {
|
||||
if (remainingSpace < 0) {
|
||||
span[i++]--;
|
||||
remainingSpace++;
|
||||
}
|
||||
else {
|
||||
span[i++]++;
|
||||
remainingSpace--;
|
||||
}
|
||||
|
||||
// just in case there are more pixels than frames...should never happen..
|
||||
if (i == span.length)i = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Users have been known to type things like "%25" and "25 %". Deal
|
||||
* with it.
|
||||
*/
|
||||
private int parseDigits(String mixedStr) {
|
||||
int result = 0;
|
||||
for (int i = 0; i < mixedStr.length(); i++) {
|
||||
char ch = mixedStr.charAt(i);
|
||||
if (Character.isDigit(ch)) {
|
||||
result = (result * 10) + Character.digit(ch, 10);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
479
jdkSrc/jdk8/javax/swing/text/html/FrameView.java
Normal file
479
jdkSrc/jdk8/javax/swing/text/html/FrameView.java
Normal file
@@ -0,0 +1,479 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.event.*;
|
||||
|
||||
import sun.swing.text.html.FrameEditorPaneTag;
|
||||
|
||||
/**
|
||||
* Implements a FrameView, intended to support the HTML
|
||||
* <FRAME> tag. Supports the frameborder, scrolling,
|
||||
* marginwidth and marginheight attributes.
|
||||
*
|
||||
* @author Sunita Mani
|
||||
*/
|
||||
|
||||
class FrameView extends ComponentView implements HyperlinkListener {
|
||||
|
||||
|
||||
JEditorPane htmlPane;
|
||||
JScrollPane scroller;
|
||||
boolean editable;
|
||||
float width;
|
||||
float height;
|
||||
URL src;
|
||||
/** Set to true when the component has been created. */
|
||||
private boolean createdComponent;
|
||||
|
||||
/**
|
||||
* Creates a new Frame.
|
||||
*
|
||||
* @param elem the element to represent.
|
||||
*/
|
||||
public FrameView(Element elem) {
|
||||
super(elem);
|
||||
}
|
||||
|
||||
protected Component createComponent() {
|
||||
|
||||
Element elem = getElement();
|
||||
AttributeSet attributes = elem.getAttributes();
|
||||
String srcAtt = (String)attributes.getAttribute(HTML.Attribute.SRC);
|
||||
|
||||
if ((srcAtt != null) && (!srcAtt.equals(""))) {
|
||||
try {
|
||||
URL base = ((HTMLDocument)elem.getDocument()).getBase();
|
||||
src = new URL(base, srcAtt);
|
||||
htmlPane = new FrameEditorPane();
|
||||
htmlPane.addHyperlinkListener(this);
|
||||
JEditorPane host = getHostPane();
|
||||
boolean isAutoFormSubmission = true;
|
||||
if (host != null) {
|
||||
htmlPane.setEditable(host.isEditable());
|
||||
String charset = (String) host.getClientProperty("charset");
|
||||
if (charset != null) {
|
||||
htmlPane.putClientProperty("charset", charset);
|
||||
}
|
||||
HTMLEditorKit hostKit = (HTMLEditorKit)host.getEditorKit();
|
||||
if (hostKit != null) {
|
||||
isAutoFormSubmission = hostKit.isAutoFormSubmission();
|
||||
}
|
||||
}
|
||||
htmlPane.setPage(src);
|
||||
HTMLEditorKit kit = (HTMLEditorKit)htmlPane.getEditorKit();
|
||||
if (kit != null) {
|
||||
kit.setAutoFormSubmission(isAutoFormSubmission);
|
||||
}
|
||||
|
||||
Document doc = htmlPane.getDocument();
|
||||
if (doc instanceof HTMLDocument) {
|
||||
((HTMLDocument)doc).setFrameDocumentState(true);
|
||||
}
|
||||
setMargin();
|
||||
createScrollPane();
|
||||
setBorder();
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
createdComponent = true;
|
||||
return scroller;
|
||||
}
|
||||
|
||||
JEditorPane getHostPane() {
|
||||
Container c = getContainer();
|
||||
while ((c != null) && ! (c instanceof JEditorPane)) {
|
||||
c = c.getParent();
|
||||
}
|
||||
return (JEditorPane) c;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the parent view for the FrameView.
|
||||
* Also determines if the FrameView should be editable
|
||||
* or not based on whether the JTextComponent that
|
||||
* contains it is editable.
|
||||
*
|
||||
* @param parent View
|
||||
*/
|
||||
public void setParent(View parent) {
|
||||
if (parent != null) {
|
||||
JTextComponent t = (JTextComponent)parent.getContainer();
|
||||
editable = t.isEditable();
|
||||
}
|
||||
super.setParent(parent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Also determines if the FrameView should be editable
|
||||
* or not based on whether the JTextComponent that
|
||||
* contains it is editable. And then proceeds to call
|
||||
* the superclass to do the paint().
|
||||
*
|
||||
* @param parent View
|
||||
* @see text.ComponentView#paint
|
||||
*/
|
||||
public void paint(Graphics g, Shape allocation) {
|
||||
|
||||
Container host = getContainer();
|
||||
if (host != null && htmlPane != null &&
|
||||
htmlPane.isEditable() != ((JTextComponent)host).isEditable()) {
|
||||
editable = ((JTextComponent)host).isEditable();
|
||||
htmlPane.setEditable(editable);
|
||||
}
|
||||
super.paint(g, allocation);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the marginwidth or marginheight attributes have been specified,
|
||||
* then the JEditorPane's margin's are set to the new values.
|
||||
*/
|
||||
private void setMargin() {
|
||||
int margin = 0;
|
||||
Insets in = htmlPane.getMargin();
|
||||
Insets newInsets;
|
||||
boolean modified = false;
|
||||
AttributeSet attributes = getElement().getAttributes();
|
||||
String marginStr = (String)attributes.getAttribute(HTML.Attribute.MARGINWIDTH);
|
||||
if ( in != null) {
|
||||
newInsets = new Insets(in.top, in.left, in.right, in.bottom);
|
||||
} else {
|
||||
newInsets = new Insets(0,0,0,0);
|
||||
}
|
||||
if (marginStr != null) {
|
||||
margin = Integer.parseInt(marginStr);
|
||||
if (margin > 0) {
|
||||
newInsets.left = margin;
|
||||
newInsets.right = margin;
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
marginStr = (String)attributes.getAttribute(HTML.Attribute.MARGINHEIGHT);
|
||||
if (marginStr != null) {
|
||||
margin = Integer.parseInt(marginStr);
|
||||
if (margin > 0) {
|
||||
newInsets.top = margin;
|
||||
newInsets.bottom = margin;
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
if (modified) {
|
||||
htmlPane.setMargin(newInsets);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the frameborder attribute has been specified, either in the frame,
|
||||
* or by the frames enclosing frameset, the JScrollPane's setBorder()
|
||||
* method is invoked to achieve the desired look.
|
||||
*/
|
||||
private void setBorder() {
|
||||
|
||||
AttributeSet attributes = getElement().getAttributes();
|
||||
String frameBorder = (String)attributes.getAttribute(HTML.Attribute.FRAMEBORDER);
|
||||
if ((frameBorder != null) &&
|
||||
(frameBorder.equals("no") || frameBorder.equals("0"))) {
|
||||
// make invisible borders.
|
||||
scroller.setBorder(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method creates the JScrollPane. The scrollbar policy is determined by
|
||||
* the scrolling attribute. If not defined, the default is "auto" which
|
||||
* maps to the scrollbar's being displayed as needed.
|
||||
*/
|
||||
private void createScrollPane() {
|
||||
AttributeSet attributes = getElement().getAttributes();
|
||||
String scrolling = (String)attributes.getAttribute(HTML.Attribute.SCROLLING);
|
||||
if (scrolling == null) {
|
||||
scrolling = "auto";
|
||||
}
|
||||
|
||||
if (!scrolling.equals("no")) {
|
||||
if (scrolling.equals("yes")) {
|
||||
scroller = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
|
||||
} else {
|
||||
// scrollbars will be displayed if needed
|
||||
//
|
||||
scroller = new JScrollPane();
|
||||
}
|
||||
} else {
|
||||
scroller = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_NEVER,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
}
|
||||
|
||||
JViewport vp = scroller.getViewport();
|
||||
vp.add(htmlPane);
|
||||
vp.setBackingStoreEnabled(true);
|
||||
scroller.setMinimumSize(new Dimension(5,5));
|
||||
scroller.setMaximumSize(new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds the outermost FrameSetView. It then
|
||||
* returns that FrameSetView's container.
|
||||
*/
|
||||
JEditorPane getOutermostJEditorPane() {
|
||||
|
||||
View parent = getParent();
|
||||
FrameSetView frameSetView = null;
|
||||
while (parent != null) {
|
||||
if (parent instanceof FrameSetView) {
|
||||
frameSetView = (FrameSetView)parent;
|
||||
}
|
||||
parent = parent.getParent();
|
||||
}
|
||||
if (frameSetView != null) {
|
||||
return (JEditorPane)frameSetView.getContainer();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if this frame is contained within
|
||||
* a nested frameset.
|
||||
*/
|
||||
private boolean inNestedFrameSet() {
|
||||
FrameSetView parent = (FrameSetView)getParent();
|
||||
return (parent.getParent() instanceof FrameSetView);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notification of a change relative to a
|
||||
* hyperlink. This method searches for the outermost
|
||||
* JEditorPane, and then fires an HTMLFrameHyperlinkEvent
|
||||
* to that frame. In addition, if the target is _parent,
|
||||
* and there is not nested framesets then the target is
|
||||
* reset to _top. If the target is _top, in addition to
|
||||
* firing the event to the outermost JEditorPane, this
|
||||
* method also invokes the setPage() method and explicitly
|
||||
* replaces the current document with the destination url.
|
||||
*
|
||||
* @param HyperlinkEvent
|
||||
*/
|
||||
public void hyperlinkUpdate(HyperlinkEvent evt) {
|
||||
|
||||
JEditorPane c = getOutermostJEditorPane();
|
||||
if (c == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(evt instanceof HTMLFrameHyperlinkEvent)) {
|
||||
c.fireHyperlinkUpdate(evt);
|
||||
return;
|
||||
}
|
||||
|
||||
HTMLFrameHyperlinkEvent e = (HTMLFrameHyperlinkEvent)evt;
|
||||
|
||||
if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
|
||||
String target = e.getTarget();
|
||||
String postTarget = target;
|
||||
|
||||
if (target.equals("_parent") && !inNestedFrameSet()){
|
||||
target = "_top";
|
||||
}
|
||||
|
||||
if (evt instanceof FormSubmitEvent) {
|
||||
HTMLEditorKit kit = (HTMLEditorKit)c.getEditorKit();
|
||||
if (kit != null && kit.isAutoFormSubmission()) {
|
||||
if (target.equals("_top")) {
|
||||
try {
|
||||
movePostData(c, postTarget);
|
||||
c.setPage(e.getURL());
|
||||
} catch (IOException ex) {
|
||||
// Need a way to handle exceptions
|
||||
}
|
||||
} else {
|
||||
HTMLDocument doc = (HTMLDocument)c.getDocument();
|
||||
doc.processHTMLFrameHyperlinkEvent(e);
|
||||
}
|
||||
} else {
|
||||
c.fireHyperlinkUpdate(evt);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.equals("_top")) {
|
||||
try {
|
||||
c.setPage(e.getURL());
|
||||
} catch (IOException ex) {
|
||||
// Need a way to handle exceptions
|
||||
// ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (!c.isEditable()) {
|
||||
c.fireHyperlinkUpdate(new HTMLFrameHyperlinkEvent(c,
|
||||
e.getEventType(),
|
||||
e.getURL(),
|
||||
e.getDescription(),
|
||||
getElement(),
|
||||
e.getInputEvent(),
|
||||
target));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives notification from the document that attributes were changed
|
||||
* in a location that this view is responsible for. Currently this view
|
||||
* handles changes to its SRC attribute.
|
||||
*
|
||||
* @param e the change information from the associated document
|
||||
* @param a the current allocation of the view
|
||||
* @param f the factory to use to rebuild if the view has children
|
||||
*
|
||||
*/
|
||||
public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
|
||||
|
||||
Element elem = getElement();
|
||||
AttributeSet attributes = elem.getAttributes();
|
||||
|
||||
URL oldPage = src;
|
||||
|
||||
String srcAtt = (String)attributes.getAttribute(HTML.Attribute.SRC);
|
||||
URL base = ((HTMLDocument)elem.getDocument()).getBase();
|
||||
try {
|
||||
if (!createdComponent) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object postData = movePostData(htmlPane, null);
|
||||
src = new URL(base, srcAtt);
|
||||
if (oldPage.equals(src) && (src.getRef() == null) && (postData == null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
htmlPane.setPage(src);
|
||||
Document newDoc = htmlPane.getDocument();
|
||||
if (newDoc instanceof HTMLDocument) {
|
||||
((HTMLDocument)newDoc).setFrameDocumentState(true);
|
||||
}
|
||||
} catch (MalformedURLException e1) {
|
||||
// Need a way to handle exceptions
|
||||
//e1.printStackTrace();
|
||||
} catch (IOException e2) {
|
||||
// Need a way to handle exceptions
|
||||
//e2.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move POST data from temporary storage into the target document property.
|
||||
*
|
||||
* @return the POST data or null if no data found
|
||||
*/
|
||||
private Object movePostData(JEditorPane targetPane, String frameName) {
|
||||
Object postData = null;
|
||||
JEditorPane p = getOutermostJEditorPane();
|
||||
if (p != null) {
|
||||
if (frameName == null) {
|
||||
frameName = (String) getElement().getAttributes().getAttribute(
|
||||
HTML.Attribute.NAME);
|
||||
}
|
||||
if (frameName != null) {
|
||||
String propName = FormView.PostDataProperty + "." + frameName;
|
||||
Document d = p.getDocument();
|
||||
postData = d.getProperty(propName);
|
||||
if (postData != null) {
|
||||
targetPane.getDocument().putProperty(
|
||||
FormView.PostDataProperty, postData);
|
||||
d.putProperty(propName, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return postData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the minimum span for this view along an
|
||||
* axis.
|
||||
*
|
||||
* @param axis may be either <code>View.X_AXIS</code> or
|
||||
* <code>View.Y_AXIS</code>
|
||||
* @return the preferred span; given that we do not
|
||||
* support resizing of frames, the minimum span returned
|
||||
* is the same as the preferred span
|
||||
*
|
||||
*/
|
||||
public float getMinimumSpan(int axis) {
|
||||
return 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the maximum span for this view along an
|
||||
* axis.
|
||||
*
|
||||
* @param axis may be either <code>View.X_AXIS</code> or
|
||||
* <code>View.Y_AXIS</code>
|
||||
* @return the preferred span; given that we do not
|
||||
* support resizing of frames, the maximum span returned
|
||||
* is the same as the preferred span
|
||||
*
|
||||
*/
|
||||
public float getMaximumSpan(int axis) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
/** Editor pane rendering frame of HTML document
|
||||
* It uses the same editor kits classes as outermost JEditorPane
|
||||
*/
|
||||
class FrameEditorPane extends JEditorPane implements FrameEditorPaneTag {
|
||||
public EditorKit getEditorKitForContentType(String type) {
|
||||
EditorKit editorKit = super.getEditorKitForContentType(type);
|
||||
JEditorPane outerMostJEditorPane = null;
|
||||
if ((outerMostJEditorPane = getOutermostJEditorPane()) != null) {
|
||||
EditorKit inheritedEditorKit = outerMostJEditorPane.getEditorKitForContentType(type);
|
||||
if (! editorKit.getClass().equals(inheritedEditorKit.getClass())) {
|
||||
editorKit = (EditorKit) inheritedEditorKit.clone();
|
||||
setEditorKitForContentType(type, editorKit);
|
||||
}
|
||||
}
|
||||
return editorKit;
|
||||
}
|
||||
|
||||
FrameView getFrameView() {
|
||||
return FrameView.this;
|
||||
}
|
||||
}
|
||||
}
|
||||
321
jdkSrc/jdk8/javax/swing/text/html/HRuleView.java
Normal file
321
jdkSrc/jdk8/javax/swing/text/html/HRuleView.java
Normal file
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.awt.*;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.text.*;
|
||||
import java.util.Enumeration;
|
||||
import java.lang.Integer;
|
||||
|
||||
/**
|
||||
* A view implementation to display an html horizontal
|
||||
* rule.
|
||||
*
|
||||
* @author Timothy Prinzing
|
||||
* @author Sara Swanson
|
||||
*/
|
||||
class HRuleView extends View {
|
||||
|
||||
/**
|
||||
* Creates a new view that represents an <hr> element.
|
||||
*
|
||||
* @param elem the element to create a view for
|
||||
*/
|
||||
public HRuleView(Element elem) {
|
||||
super(elem);
|
||||
setPropertiesFromAttributes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update any cached values that come from attributes.
|
||||
*/
|
||||
protected void setPropertiesFromAttributes() {
|
||||
StyleSheet sheet = ((HTMLDocument)getDocument()).getStyleSheet();
|
||||
AttributeSet eAttr = getElement().getAttributes();
|
||||
attr = sheet.getViewAttributes(this);
|
||||
|
||||
alignment = StyleConstants.ALIGN_CENTER;
|
||||
size = 0;
|
||||
noshade = null;
|
||||
widthValue = null;
|
||||
|
||||
if (attr != null) {
|
||||
// getAlignment() returns ALIGN_LEFT by default, and HR should
|
||||
// use ALIGN_CENTER by default, so we check if the alignment
|
||||
// attribute is actually defined
|
||||
if (attr.getAttribute(StyleConstants.Alignment) != null) {
|
||||
alignment = StyleConstants.getAlignment(attr);
|
||||
}
|
||||
|
||||
noshade = (String)eAttr.getAttribute(HTML.Attribute.NOSHADE);
|
||||
Object value = eAttr.getAttribute(HTML.Attribute.SIZE);
|
||||
if (value != null && (value instanceof String)) {
|
||||
try {
|
||||
size = Integer.parseInt((String)value);
|
||||
} catch (NumberFormatException e) {
|
||||
size = 1;
|
||||
}
|
||||
}
|
||||
value = attr.getAttribute(CSS.Attribute.WIDTH);
|
||||
if (value != null && (value instanceof CSS.LengthValue)) {
|
||||
widthValue = (CSS.LengthValue)value;
|
||||
}
|
||||
topMargin = getLength(CSS.Attribute.MARGIN_TOP, attr);
|
||||
bottomMargin = getLength(CSS.Attribute.MARGIN_BOTTOM, attr);
|
||||
leftMargin = getLength(CSS.Attribute.MARGIN_LEFT, attr);
|
||||
rightMargin = getLength(CSS.Attribute.MARGIN_RIGHT, attr);
|
||||
}
|
||||
else {
|
||||
topMargin = bottomMargin = leftMargin = rightMargin = 0;
|
||||
}
|
||||
size = Math.max(2, size);
|
||||
}
|
||||
|
||||
// This will be removed and centralized at some point, need to unify this
|
||||
// and avoid private classes.
|
||||
private float getLength(CSS.Attribute key, AttributeSet a) {
|
||||
CSS.LengthValue lv = (CSS.LengthValue) a.getAttribute(key);
|
||||
float len = (lv != null) ? lv.getValue() : 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
// --- View methods ---------------------------------------------
|
||||
|
||||
/**
|
||||
* Paints the view.
|
||||
*
|
||||
* @param g the graphics context
|
||||
* @param a the allocation region for the view
|
||||
* @see View#paint
|
||||
*/
|
||||
public void paint(Graphics g, Shape a) {
|
||||
Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a :
|
||||
a.getBounds();
|
||||
int x = 0;
|
||||
int y = alloc.y + SPACE_ABOVE + (int)topMargin;
|
||||
int width = alloc.width - (int)(leftMargin + rightMargin);
|
||||
if (widthValue != null) {
|
||||
width = (int)widthValue.getValue((float)width);
|
||||
}
|
||||
int height = alloc.height - (SPACE_ABOVE + SPACE_BELOW +
|
||||
(int)topMargin + (int)bottomMargin);
|
||||
if (size > 0)
|
||||
height = size;
|
||||
|
||||
// Align the rule horizontally.
|
||||
switch (alignment) {
|
||||
case StyleConstants.ALIGN_CENTER:
|
||||
x = alloc.x + (alloc.width / 2) - (width / 2);
|
||||
break;
|
||||
case StyleConstants.ALIGN_RIGHT:
|
||||
x = alloc.x + alloc.width - width - (int)rightMargin;
|
||||
break;
|
||||
case StyleConstants.ALIGN_LEFT:
|
||||
default:
|
||||
x = alloc.x + (int)leftMargin;
|
||||
break;
|
||||
}
|
||||
|
||||
// Paint either a shaded rule or a solid line.
|
||||
if (noshade != null) {
|
||||
g.setColor(Color.black);
|
||||
g.fillRect(x, y, width, height);
|
||||
}
|
||||
else {
|
||||
Color bg = getContainer().getBackground();
|
||||
Color bottom, top;
|
||||
if (bg == null || bg.equals(Color.white)) {
|
||||
top = Color.darkGray;
|
||||
bottom = Color.lightGray;
|
||||
}
|
||||
else {
|
||||
top = Color.darkGray;
|
||||
bottom = Color.white;
|
||||
}
|
||||
g.setColor(bottom);
|
||||
g.drawLine(x + width - 1, y, x + width - 1, y + height - 1);
|
||||
g.drawLine(x, y + height - 1, x + width - 1, y + height - 1);
|
||||
g.setColor(top);
|
||||
g.drawLine(x, y, x + width - 1, y);
|
||||
g.drawLine(x, y, x, y + height - 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the desired shape of the rule... this is
|
||||
* basically the preferred size of the border.
|
||||
*
|
||||
* @param axis may be either X_AXIS or Y_AXIS
|
||||
* @return the desired span
|
||||
* @see View#getPreferredSpan
|
||||
*/
|
||||
public float getPreferredSpan(int axis) {
|
||||
switch (axis) {
|
||||
case View.X_AXIS:
|
||||
return 1;
|
||||
case View.Y_AXIS:
|
||||
if (size > 0) {
|
||||
return size + SPACE_ABOVE + SPACE_BELOW + topMargin +
|
||||
bottomMargin;
|
||||
} else {
|
||||
if (noshade != null) {
|
||||
return 2 + SPACE_ABOVE + SPACE_BELOW + topMargin +
|
||||
bottomMargin;
|
||||
} else {
|
||||
return SPACE_ABOVE + SPACE_BELOW + topMargin +bottomMargin;
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid axis: " + axis);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the resize weight for the axis.
|
||||
* The rule is: rigid vertically and flexible horizontally.
|
||||
*
|
||||
* @param axis may be either X_AXIS or Y_AXIS
|
||||
* @return the weight
|
||||
*/
|
||||
public int getResizeWeight(int axis) {
|
||||
if (axis == View.X_AXIS) {
|
||||
return 1;
|
||||
} else if (axis == View.Y_AXIS) {
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines how attractive a break opportunity in
|
||||
* this view is. This is implemented to request a forced break.
|
||||
*
|
||||
* @param axis may be either View.X_AXIS or View.Y_AXIS
|
||||
* @param pos the potential location of the start of the
|
||||
* broken view (greater than or equal to zero).
|
||||
* This may be useful for calculating tab
|
||||
* positions.
|
||||
* @param len specifies the relative length from <em>pos</em>
|
||||
* where a potential break is desired. The value must be greater
|
||||
* than or equal to zero.
|
||||
* @return the weight, which should be a value between
|
||||
* ForcedBreakWeight and BadBreakWeight.
|
||||
*/
|
||||
public int getBreakWeight(int axis, float pos, float len) {
|
||||
if (axis == X_AXIS) {
|
||||
return ForcedBreakWeight;
|
||||
}
|
||||
return BadBreakWeight;
|
||||
}
|
||||
|
||||
public View breakView(int axis, int offset, float pos, float len) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a mapping from the document model coordinate space
|
||||
* to the coordinate space of the view mapped to it.
|
||||
*
|
||||
* @param pos the position to convert
|
||||
* @param a the allocated region to render into
|
||||
* @return the bounding box of the given position
|
||||
* @exception BadLocationException if the given position does not
|
||||
* represent a valid location in the associated document
|
||||
* @see View#modelToView
|
||||
*/
|
||||
public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException {
|
||||
int p0 = getStartOffset();
|
||||
int p1 = getEndOffset();
|
||||
if ((pos >= p0) && (pos <= p1)) {
|
||||
Rectangle r = a.getBounds();
|
||||
if (pos == p1) {
|
||||
r.x += r.width;
|
||||
}
|
||||
r.width = 0;
|
||||
return r;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a mapping from the view coordinate space to the logical
|
||||
* coordinate space of the model.
|
||||
*
|
||||
* @param x the X coordinate
|
||||
* @param y the Y coordinate
|
||||
* @param a the allocated region to render into
|
||||
* @return the location within the model that best represents the
|
||||
* given point of view
|
||||
* @see View#viewToModel
|
||||
*/
|
||||
public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) {
|
||||
Rectangle alloc = (Rectangle) a;
|
||||
if (x < alloc.x + (alloc.width / 2)) {
|
||||
bias[0] = Position.Bias.Forward;
|
||||
return getStartOffset();
|
||||
}
|
||||
bias[0] = Position.Bias.Backward;
|
||||
return getEndOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the attributes to use when rendering. This is
|
||||
* implemented to multiplex the attributes specified in the
|
||||
* model with a StyleSheet.
|
||||
*/
|
||||
public AttributeSet getAttributes() {
|
||||
return attr;
|
||||
}
|
||||
|
||||
public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
|
||||
super.changedUpdate(changes, a, f);
|
||||
int pos = changes.getOffset();
|
||||
if (pos <= getStartOffset() && (pos + changes.getLength()) >=
|
||||
getEndOffset()) {
|
||||
setPropertiesFromAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
// --- variables ------------------------------------------------
|
||||
|
||||
private float topMargin;
|
||||
private float bottomMargin;
|
||||
private float leftMargin;
|
||||
private float rightMargin;
|
||||
private int alignment = StyleConstants.ALIGN_CENTER;
|
||||
private String noshade = null;
|
||||
private int size = 0;
|
||||
private CSS.LengthValue widthValue;
|
||||
|
||||
private static final int SPACE_ABOVE = 3;
|
||||
private static final int SPACE_BELOW = 3;
|
||||
|
||||
/** View Attributes. */
|
||||
private AttributeSet attr;
|
||||
}
|
||||
697
jdkSrc/jdk8/javax/swing/text/html/HTML.java
Normal file
697
jdkSrc/jdk8/javax/swing/text/html/HTML.java
Normal file
@@ -0,0 +1,697 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Hashtable;
|
||||
import javax.swing.text.AttributeSet;
|
||||
import javax.swing.text.StyleConstants;
|
||||
import javax.swing.text.StyleContext;
|
||||
|
||||
/**
|
||||
* Constants used in the <code>HTMLDocument</code>. These
|
||||
* are basically tag and attribute definitions.
|
||||
*
|
||||
* @author Timothy Prinzing
|
||||
* @author Sunita Mani
|
||||
*
|
||||
*/
|
||||
public class HTML {
|
||||
|
||||
/**
|
||||
* Typesafe enumeration for an HTML tag. Although the
|
||||
* set of HTML tags is a closed set, we have left the
|
||||
* set open so that people can add their own tag types
|
||||
* to their custom parser and still communicate to the
|
||||
* reader.
|
||||
*/
|
||||
public static class Tag {
|
||||
|
||||
/** @since 1.3 */
|
||||
public Tag() {}
|
||||
|
||||
/**
|
||||
* Creates a new <code>Tag</code> with the specified <code>id</code>,
|
||||
* and with <code>causesBreak</code> and <code>isBlock</code>
|
||||
* set to <code>false</code>.
|
||||
*
|
||||
* @param id the id of the new tag
|
||||
*/
|
||||
protected Tag(String id) {
|
||||
this(id, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>Tag</code> with the specified <code>id</code>;
|
||||
* <code>causesBreak</code> and <code>isBlock</code> are defined
|
||||
* by the user.
|
||||
*
|
||||
* @param id the id of the new tag
|
||||
* @param causesBreak <code>true</code> if this tag
|
||||
* causes a break to the flow of data
|
||||
* @param isBlock <code>true</code> if the tag is used
|
||||
* to add structure to a document
|
||||
*/
|
||||
protected Tag(String id, boolean causesBreak, boolean isBlock) {
|
||||
name = id;
|
||||
this.breakTag = causesBreak;
|
||||
this.blockTag = isBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if this tag is a block
|
||||
* tag, which is a tag used to add structure to a
|
||||
* document.
|
||||
*
|
||||
* @return <code>true</code> if this tag is a block
|
||||
* tag, otherwise returns <code>false</code>
|
||||
*/
|
||||
public boolean isBlock() {
|
||||
return blockTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if this tag causes a
|
||||
* line break to the flow of data, otherwise returns
|
||||
* <code>false</code>.
|
||||
*
|
||||
* @return <code>true</code> if this tag causes a
|
||||
* line break to the flow of data, otherwise returns
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean breaksFlow() {
|
||||
return breakTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if this tag is pre-formatted,
|
||||
* which is true if the tag is either <code>PRE</code> or
|
||||
* <code>TEXTAREA</code>.
|
||||
*
|
||||
* @return <code>true</code> if this tag is pre-formatted,
|
||||
* otherwise returns <code>false</code>
|
||||
*/
|
||||
public boolean isPreformatted() {
|
||||
return (this == PRE || this == TEXTAREA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string representation of the
|
||||
* tag.
|
||||
*
|
||||
* @return the <code>String</code> representation of the tag
|
||||
*/
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if this tag is considered to be a paragraph
|
||||
* in the internal HTML model. <code>false</code> - otherwise.
|
||||
*
|
||||
* @return <code>true</code> if this tag is considered to be a paragraph
|
||||
* in the internal HTML model. <code>false</code> - otherwise.
|
||||
* @see HTMLDocument.HTMLReader.ParagraphAction
|
||||
*/
|
||||
boolean isParagraph() {
|
||||
return (
|
||||
this == P
|
||||
|| this == IMPLIED
|
||||
|| this == DT
|
||||
|| this == H1
|
||||
|| this == H2
|
||||
|| this == H3
|
||||
|| this == H4
|
||||
|| this == H5
|
||||
|| this == H6
|
||||
);
|
||||
}
|
||||
|
||||
boolean blockTag;
|
||||
boolean breakTag;
|
||||
String name;
|
||||
boolean unknown;
|
||||
|
||||
// --- Tag Names -----------------------------------
|
||||
|
||||
public static final Tag A = new Tag("a");
|
||||
public static final Tag ADDRESS = new Tag("address");
|
||||
public static final Tag APPLET = new Tag("applet");
|
||||
public static final Tag AREA = new Tag("area");
|
||||
public static final Tag B = new Tag("b");
|
||||
public static final Tag BASE = new Tag("base");
|
||||
public static final Tag BASEFONT = new Tag("basefont");
|
||||
public static final Tag BIG = new Tag("big");
|
||||
public static final Tag BLOCKQUOTE = new Tag("blockquote", true, true);
|
||||
public static final Tag BODY = new Tag("body", true, true);
|
||||
public static final Tag BR = new Tag("br", true, false);
|
||||
public static final Tag CAPTION = new Tag("caption");
|
||||
public static final Tag CENTER = new Tag("center", true, false);
|
||||
public static final Tag CITE = new Tag("cite");
|
||||
public static final Tag CODE = new Tag("code");
|
||||
public static final Tag DD = new Tag("dd", true, true);
|
||||
public static final Tag DFN = new Tag("dfn");
|
||||
public static final Tag DIR = new Tag("dir", true, true);
|
||||
public static final Tag DIV = new Tag("div", true, true);
|
||||
public static final Tag DL = new Tag("dl", true, true);
|
||||
public static final Tag DT = new Tag("dt", true, true);
|
||||
public static final Tag EM = new Tag("em");
|
||||
public static final Tag FONT = new Tag("font");
|
||||
public static final Tag FORM = new Tag("form", true, false);
|
||||
public static final Tag FRAME = new Tag("frame");
|
||||
public static final Tag FRAMESET = new Tag("frameset");
|
||||
public static final Tag H1 = new Tag("h1", true, true);
|
||||
public static final Tag H2 = new Tag("h2", true, true);
|
||||
public static final Tag H3 = new Tag("h3", true, true);
|
||||
public static final Tag H4 = new Tag("h4", true, true);
|
||||
public static final Tag H5 = new Tag("h5", true, true);
|
||||
public static final Tag H6 = new Tag("h6", true, true);
|
||||
public static final Tag HEAD = new Tag("head", true, true);
|
||||
public static final Tag HR = new Tag("hr", true, false);
|
||||
public static final Tag HTML = new Tag("html", true, false);
|
||||
public static final Tag I = new Tag("i");
|
||||
public static final Tag IMG = new Tag("img");
|
||||
public static final Tag INPUT = new Tag("input");
|
||||
public static final Tag ISINDEX = new Tag("isindex", true, false);
|
||||
public static final Tag KBD = new Tag("kbd");
|
||||
public static final Tag LI = new Tag("li", true, true);
|
||||
public static final Tag LINK = new Tag("link");
|
||||
public static final Tag MAP = new Tag("map");
|
||||
public static final Tag MENU = new Tag("menu", true, true);
|
||||
public static final Tag META = new Tag("meta");
|
||||
/*public*/ static final Tag NOBR = new Tag("nobr");
|
||||
public static final Tag NOFRAMES = new Tag("noframes", true, true);
|
||||
public static final Tag OBJECT = new Tag("object");
|
||||
public static final Tag OL = new Tag("ol", true, true);
|
||||
public static final Tag OPTION = new Tag("option");
|
||||
public static final Tag P = new Tag("p", true, true);
|
||||
public static final Tag PARAM = new Tag("param");
|
||||
public static final Tag PRE = new Tag("pre", true, true);
|
||||
public static final Tag SAMP = new Tag("samp");
|
||||
public static final Tag SCRIPT = new Tag("script");
|
||||
public static final Tag SELECT = new Tag("select");
|
||||
public static final Tag SMALL = new Tag("small");
|
||||
public static final Tag SPAN = new Tag("span");
|
||||
public static final Tag STRIKE = new Tag("strike");
|
||||
public static final Tag S = new Tag("s");
|
||||
public static final Tag STRONG = new Tag("strong");
|
||||
public static final Tag STYLE = new Tag("style");
|
||||
public static final Tag SUB = new Tag("sub");
|
||||
public static final Tag SUP = new Tag("sup");
|
||||
public static final Tag TABLE = new Tag("table", false, true);
|
||||
public static final Tag TD = new Tag("td", true, true);
|
||||
public static final Tag TEXTAREA = new Tag("textarea");
|
||||
public static final Tag TH = new Tag("th", true, true);
|
||||
public static final Tag TITLE = new Tag("title", true, true);
|
||||
public static final Tag TR = new Tag("tr", false, true);
|
||||
public static final Tag TT = new Tag("tt");
|
||||
public static final Tag U = new Tag("u");
|
||||
public static final Tag UL = new Tag("ul", true, true);
|
||||
public static final Tag VAR = new Tag("var");
|
||||
|
||||
/**
|
||||
* All text content must be in a paragraph element.
|
||||
* If a paragraph didn't exist when content was
|
||||
* encountered, a paragraph is manufactured.
|
||||
* <p>
|
||||
* This is a tag synthesized by the HTML reader.
|
||||
* Since elements are identified by their tag type,
|
||||
* we create a some fake tag types to mark the elements
|
||||
* that were manufactured.
|
||||
*/
|
||||
public static final Tag IMPLIED = new Tag("p-implied");
|
||||
|
||||
/**
|
||||
* All text content is labeled with this tag.
|
||||
* <p>
|
||||
* This is a tag synthesized by the HTML reader.
|
||||
* Since elements are identified by their tag type,
|
||||
* we create a some fake tag types to mark the elements
|
||||
* that were manufactured.
|
||||
*/
|
||||
public static final Tag CONTENT = new Tag("content");
|
||||
|
||||
/**
|
||||
* All comments are labeled with this tag.
|
||||
* <p>
|
||||
* This is a tag synthesized by the HTML reader.
|
||||
* Since elements are identified by their tag type,
|
||||
* we create a some fake tag types to mark the elements
|
||||
* that were manufactured.
|
||||
*/
|
||||
public static final Tag COMMENT = new Tag("comment");
|
||||
|
||||
static final Tag allTags[] = {
|
||||
A, ADDRESS, APPLET, AREA, B, BASE, BASEFONT, BIG,
|
||||
BLOCKQUOTE, BODY, BR, CAPTION, CENTER, CITE, CODE,
|
||||
DD, DFN, DIR, DIV, DL, DT, EM, FONT, FORM, FRAME,
|
||||
FRAMESET, H1, H2, H3, H4, H5, H6, HEAD, HR, HTML,
|
||||
I, IMG, INPUT, ISINDEX, KBD, LI, LINK, MAP, MENU,
|
||||
META, NOBR, NOFRAMES, OBJECT, OL, OPTION, P, PARAM,
|
||||
PRE, SAMP, SCRIPT, SELECT, SMALL, SPAN, STRIKE, S,
|
||||
STRONG, STYLE, SUB, SUP, TABLE, TD, TEXTAREA,
|
||||
TH, TITLE, TR, TT, U, UL, VAR
|
||||
};
|
||||
|
||||
static {
|
||||
// Force HTMLs static initialize to be loaded.
|
||||
getTag("html");
|
||||
}
|
||||
}
|
||||
|
||||
// There is no unique instance of UnknownTag, so we allow it to be
|
||||
// Serializable.
|
||||
public static class UnknownTag extends Tag implements Serializable {
|
||||
|
||||
/**
|
||||
* Creates a new <code>UnknownTag</code> with the specified
|
||||
* <code>id</code>.
|
||||
* @param id the id of the new tag
|
||||
*/
|
||||
public UnknownTag(String id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash code which corresponds to the string
|
||||
* for this tag.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return toString().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object to the specified object.
|
||||
* The result is <code>true</code> if and only if the argument is not
|
||||
* <code>null</code> and is an <code>UnknownTag</code> object
|
||||
* with the same name.
|
||||
*
|
||||
* @param obj the object to compare this tag with
|
||||
* @return <code>true</code> if the objects are equal;
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof UnknownTag) {
|
||||
return toString().equals(obj.toString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void writeObject(java.io.ObjectOutputStream s)
|
||||
throws IOException {
|
||||
s.defaultWriteObject();
|
||||
s.writeBoolean(blockTag);
|
||||
s.writeBoolean(breakTag);
|
||||
s.writeBoolean(unknown);
|
||||
s.writeObject(name);
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream s)
|
||||
throws ClassNotFoundException, IOException {
|
||||
s.defaultReadObject();
|
||||
blockTag = s.readBoolean();
|
||||
breakTag = s.readBoolean();
|
||||
unknown = s.readBoolean();
|
||||
name = (String)s.readObject();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Typesafe enumeration representing an HTML
|
||||
* attribute.
|
||||
*/
|
||||
public static final class Attribute {
|
||||
|
||||
/**
|
||||
* Creates a new <code>Attribute</code> with the specified
|
||||
* <code>id</code>.
|
||||
*
|
||||
* @param id the id of the new <code>Attribute</code>
|
||||
*/
|
||||
Attribute(String id) {
|
||||
name = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string representation of this attribute.
|
||||
* @return the string representation of this attribute
|
||||
*/
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private String name;
|
||||
|
||||
public static final Attribute SIZE = new Attribute("size");
|
||||
public static final Attribute COLOR = new Attribute("color");
|
||||
public static final Attribute CLEAR = new Attribute("clear");
|
||||
public static final Attribute BACKGROUND = new Attribute("background");
|
||||
public static final Attribute BGCOLOR = new Attribute("bgcolor");
|
||||
public static final Attribute TEXT = new Attribute("text");
|
||||
public static final Attribute LINK = new Attribute("link");
|
||||
public static final Attribute VLINK = new Attribute("vlink");
|
||||
public static final Attribute ALINK = new Attribute("alink");
|
||||
public static final Attribute WIDTH = new Attribute("width");
|
||||
public static final Attribute HEIGHT = new Attribute("height");
|
||||
public static final Attribute ALIGN = new Attribute("align");
|
||||
public static final Attribute NAME = new Attribute("name");
|
||||
public static final Attribute HREF = new Attribute("href");
|
||||
public static final Attribute REL = new Attribute("rel");
|
||||
public static final Attribute REV = new Attribute("rev");
|
||||
public static final Attribute TITLE = new Attribute("title");
|
||||
public static final Attribute TARGET = new Attribute("target");
|
||||
public static final Attribute SHAPE = new Attribute("shape");
|
||||
public static final Attribute COORDS = new Attribute("coords");
|
||||
public static final Attribute ISMAP = new Attribute("ismap");
|
||||
public static final Attribute NOHREF = new Attribute("nohref");
|
||||
public static final Attribute ALT = new Attribute("alt");
|
||||
public static final Attribute ID = new Attribute("id");
|
||||
public static final Attribute SRC = new Attribute("src");
|
||||
public static final Attribute HSPACE = new Attribute("hspace");
|
||||
public static final Attribute VSPACE = new Attribute("vspace");
|
||||
public static final Attribute USEMAP = new Attribute("usemap");
|
||||
public static final Attribute LOWSRC = new Attribute("lowsrc");
|
||||
public static final Attribute CODEBASE = new Attribute("codebase");
|
||||
public static final Attribute CODE = new Attribute("code");
|
||||
public static final Attribute ARCHIVE = new Attribute("archive");
|
||||
public static final Attribute VALUE = new Attribute("value");
|
||||
public static final Attribute VALUETYPE = new Attribute("valuetype");
|
||||
public static final Attribute TYPE = new Attribute("type");
|
||||
public static final Attribute CLASS = new Attribute("class");
|
||||
public static final Attribute STYLE = new Attribute("style");
|
||||
public static final Attribute LANG = new Attribute("lang");
|
||||
public static final Attribute FACE = new Attribute("face");
|
||||
public static final Attribute DIR = new Attribute("dir");
|
||||
public static final Attribute DECLARE = new Attribute("declare");
|
||||
public static final Attribute CLASSID = new Attribute("classid");
|
||||
public static final Attribute DATA = new Attribute("data");
|
||||
public static final Attribute CODETYPE = new Attribute("codetype");
|
||||
public static final Attribute STANDBY = new Attribute("standby");
|
||||
public static final Attribute BORDER = new Attribute("border");
|
||||
public static final Attribute SHAPES = new Attribute("shapes");
|
||||
public static final Attribute NOSHADE = new Attribute("noshade");
|
||||
public static final Attribute COMPACT = new Attribute("compact");
|
||||
public static final Attribute START = new Attribute("start");
|
||||
public static final Attribute ACTION = new Attribute("action");
|
||||
public static final Attribute METHOD = new Attribute("method");
|
||||
public static final Attribute ENCTYPE = new Attribute("enctype");
|
||||
public static final Attribute CHECKED = new Attribute("checked");
|
||||
public static final Attribute MAXLENGTH = new Attribute("maxlength");
|
||||
public static final Attribute MULTIPLE = new Attribute("multiple");
|
||||
public static final Attribute SELECTED = new Attribute("selected");
|
||||
public static final Attribute ROWS = new Attribute("rows");
|
||||
public static final Attribute COLS = new Attribute("cols");
|
||||
public static final Attribute DUMMY = new Attribute("dummy");
|
||||
public static final Attribute CELLSPACING = new Attribute("cellspacing");
|
||||
public static final Attribute CELLPADDING = new Attribute("cellpadding");
|
||||
public static final Attribute VALIGN = new Attribute("valign");
|
||||
public static final Attribute HALIGN = new Attribute("halign");
|
||||
public static final Attribute NOWRAP = new Attribute("nowrap");
|
||||
public static final Attribute ROWSPAN = new Attribute("rowspan");
|
||||
public static final Attribute COLSPAN = new Attribute("colspan");
|
||||
public static final Attribute PROMPT = new Attribute("prompt");
|
||||
public static final Attribute HTTPEQUIV = new Attribute("http-equiv");
|
||||
public static final Attribute CONTENT = new Attribute("content");
|
||||
public static final Attribute LANGUAGE = new Attribute("language");
|
||||
public static final Attribute VERSION = new Attribute("version");
|
||||
public static final Attribute N = new Attribute("n");
|
||||
public static final Attribute FRAMEBORDER = new Attribute("frameborder");
|
||||
public static final Attribute MARGINWIDTH = new Attribute("marginwidth");
|
||||
public static final Attribute MARGINHEIGHT = new Attribute("marginheight");
|
||||
public static final Attribute SCROLLING = new Attribute("scrolling");
|
||||
public static final Attribute NORESIZE = new Attribute("noresize");
|
||||
public static final Attribute ENDTAG = new Attribute("endtag");
|
||||
public static final Attribute COMMENT = new Attribute("comment");
|
||||
static final Attribute MEDIA = new Attribute("media");
|
||||
|
||||
static final Attribute allAttributes[] = {
|
||||
FACE,
|
||||
COMMENT,
|
||||
SIZE,
|
||||
COLOR,
|
||||
CLEAR,
|
||||
BACKGROUND,
|
||||
BGCOLOR,
|
||||
TEXT,
|
||||
LINK,
|
||||
VLINK,
|
||||
ALINK,
|
||||
WIDTH,
|
||||
HEIGHT,
|
||||
ALIGN,
|
||||
NAME,
|
||||
HREF,
|
||||
REL,
|
||||
REV,
|
||||
TITLE,
|
||||
TARGET,
|
||||
SHAPE,
|
||||
COORDS,
|
||||
ISMAP,
|
||||
NOHREF,
|
||||
ALT,
|
||||
ID,
|
||||
SRC,
|
||||
HSPACE,
|
||||
VSPACE,
|
||||
USEMAP,
|
||||
LOWSRC,
|
||||
CODEBASE,
|
||||
CODE,
|
||||
ARCHIVE,
|
||||
VALUE,
|
||||
VALUETYPE,
|
||||
TYPE,
|
||||
CLASS,
|
||||
STYLE,
|
||||
LANG,
|
||||
DIR,
|
||||
DECLARE,
|
||||
CLASSID,
|
||||
DATA,
|
||||
CODETYPE,
|
||||
STANDBY,
|
||||
BORDER,
|
||||
SHAPES,
|
||||
NOSHADE,
|
||||
COMPACT,
|
||||
START,
|
||||
ACTION,
|
||||
METHOD,
|
||||
ENCTYPE,
|
||||
CHECKED,
|
||||
MAXLENGTH,
|
||||
MULTIPLE,
|
||||
SELECTED,
|
||||
ROWS,
|
||||
COLS,
|
||||
DUMMY,
|
||||
CELLSPACING,
|
||||
CELLPADDING,
|
||||
VALIGN,
|
||||
HALIGN,
|
||||
NOWRAP,
|
||||
ROWSPAN,
|
||||
COLSPAN,
|
||||
PROMPT,
|
||||
HTTPEQUIV,
|
||||
CONTENT,
|
||||
LANGUAGE,
|
||||
VERSION,
|
||||
N,
|
||||
FRAMEBORDER,
|
||||
MARGINWIDTH,
|
||||
MARGINHEIGHT,
|
||||
SCROLLING,
|
||||
NORESIZE,
|
||||
MEDIA,
|
||||
ENDTAG
|
||||
};
|
||||
}
|
||||
|
||||
// The secret to 73, is that, given that the Hashtable contents
|
||||
// never change once the static initialization happens, the initial size
|
||||
// that the hashtable grew to was determined, and then that very size
|
||||
// is used.
|
||||
//
|
||||
private static final Hashtable<String, Tag> tagHashtable = new Hashtable<String, Tag>(73);
|
||||
|
||||
/** Maps from StyleConstant key to HTML.Tag. */
|
||||
private static final Hashtable<Object, Tag> scMapping = new Hashtable<Object, Tag>(8);
|
||||
|
||||
static {
|
||||
|
||||
for (int i = 0; i < Tag.allTags.length; i++ ) {
|
||||
tagHashtable.put(Tag.allTags[i].toString(), Tag.allTags[i]);
|
||||
StyleContext.registerStaticAttributeKey(Tag.allTags[i]);
|
||||
}
|
||||
StyleContext.registerStaticAttributeKey(Tag.IMPLIED);
|
||||
StyleContext.registerStaticAttributeKey(Tag.CONTENT);
|
||||
StyleContext.registerStaticAttributeKey(Tag.COMMENT);
|
||||
for (int i = 0; i < Attribute.allAttributes.length; i++) {
|
||||
StyleContext.registerStaticAttributeKey(Attribute.
|
||||
allAttributes[i]);
|
||||
}
|
||||
StyleContext.registerStaticAttributeKey(HTML.NULL_ATTRIBUTE_VALUE);
|
||||
scMapping.put(StyleConstants.Bold, Tag.B);
|
||||
scMapping.put(StyleConstants.Italic, Tag.I);
|
||||
scMapping.put(StyleConstants.Underline, Tag.U);
|
||||
scMapping.put(StyleConstants.StrikeThrough, Tag.STRIKE);
|
||||
scMapping.put(StyleConstants.Superscript, Tag.SUP);
|
||||
scMapping.put(StyleConstants.Subscript, Tag.SUB);
|
||||
scMapping.put(StyleConstants.FontFamily, Tag.FONT);
|
||||
scMapping.put(StyleConstants.FontSize, Tag.FONT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of actual HTML tags that
|
||||
* are recognized by the default HTML reader.
|
||||
* This set does not include tags that are
|
||||
* manufactured by the reader.
|
||||
*/
|
||||
public static Tag[] getAllTags() {
|
||||
Tag[] tags = new Tag[Tag.allTags.length];
|
||||
System.arraycopy(Tag.allTags, 0, tags, 0, Tag.allTags.length);
|
||||
return tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a tag constant for a well-known tag name (i.e. one of
|
||||
* the tags in the set {A, ADDRESS, APPLET, AREA, B,
|
||||
* BASE, BASEFONT, BIG,
|
||||
* BLOCKQUOTE, BODY, BR, CAPTION, CENTER, CITE, CODE,
|
||||
* DD, DFN, DIR, DIV, DL, DT, EM, FONT, FORM, FRAME,
|
||||
* FRAMESET, H1, H2, H3, H4, H5, H6, HEAD, HR, HTML,
|
||||
* I, IMG, INPUT, ISINDEX, KBD, LI, LINK, MAP, MENU,
|
||||
* META, NOBR, NOFRAMES, OBJECT, OL, OPTION, P, PARAM,
|
||||
* PRE, SAMP, SCRIPT, SELECT, SMALL, SPAN, STRIKE, S,
|
||||
* STRONG, STYLE, SUB, SUP, TABLE, TD, TEXTAREA,
|
||||
* TH, TITLE, TR, TT, U, UL, VAR}. If the given
|
||||
* name does not represent one of the well-known tags, then
|
||||
* <code>null</code> will be returned.
|
||||
*
|
||||
* @param tagName the <code>String</code> name requested
|
||||
* @return a tag constant corresponding to the <code>tagName</code>,
|
||||
* or <code>null</code> if not found
|
||||
*/
|
||||
public static Tag getTag(String tagName) {
|
||||
|
||||
Tag t = tagHashtable.get(tagName);
|
||||
return (t == null ? null : t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTML <code>Tag</code> associated with the
|
||||
* <code>StyleConstants</code> key <code>sc</code>.
|
||||
* If no matching <code>Tag</code> is found, returns
|
||||
* <code>null</code>.
|
||||
*
|
||||
* @param sc the <code>StyleConstants</code> key
|
||||
* @return tag which corresponds to <code>sc</code>, or
|
||||
* <code>null</code> if not found
|
||||
*/
|
||||
static Tag getTagForStyleConstantsKey(StyleConstants sc) {
|
||||
return scMapping.get(sc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches an integer attribute value. Attribute values
|
||||
* are stored as a string, and this is a convenience method
|
||||
* to convert to an actual integer.
|
||||
*
|
||||
* @param attr the set of attributes to use to try to fetch a value
|
||||
* @param key the key to use to fetch the value
|
||||
* @param def the default value to use if the attribute isn't
|
||||
* defined or there is an error converting to an integer
|
||||
*/
|
||||
public static int getIntegerAttributeValue(AttributeSet attr,
|
||||
Attribute key, int def) {
|
||||
int value = def;
|
||||
String istr = (String) attr.getAttribute(key);
|
||||
if (istr != null) {
|
||||
try {
|
||||
value = Integer.valueOf(istr).intValue();
|
||||
} catch (NumberFormatException e) {
|
||||
value = def;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// This is used in cases where the value for the attribute has not
|
||||
// been specified.
|
||||
//
|
||||
public static final String NULL_ATTRIBUTE_VALUE = "#DEFAULT";
|
||||
|
||||
// size determined similar to size of tagHashtable
|
||||
private static final Hashtable<String, Attribute> attHashtable = new Hashtable<String, Attribute>(77);
|
||||
|
||||
static {
|
||||
|
||||
for (int i = 0; i < Attribute.allAttributes.length; i++ ) {
|
||||
attHashtable.put(Attribute.allAttributes[i].toString(), Attribute.allAttributes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of HTML attributes recognized.
|
||||
* @return the set of HTML attributes recognized
|
||||
*/
|
||||
public static Attribute[] getAllAttributeKeys() {
|
||||
Attribute[] attributes = new Attribute[Attribute.allAttributes.length];
|
||||
System.arraycopy(Attribute.allAttributes, 0,
|
||||
attributes, 0, Attribute.allAttributes.length);
|
||||
return attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches an attribute constant for a well-known attribute name
|
||||
* (i.e. one of the attributes in the set {FACE, COMMENT, SIZE,
|
||||
* COLOR, CLEAR, BACKGROUND, BGCOLOR, TEXT, LINK, VLINK, ALINK,
|
||||
* WIDTH, HEIGHT, ALIGN, NAME, HREF, REL, REV, TITLE, TARGET,
|
||||
* SHAPE, COORDS, ISMAP, NOHREF, ALT, ID, SRC, HSPACE, VSPACE,
|
||||
* USEMAP, LOWSRC, CODEBASE, CODE, ARCHIVE, VALUE, VALUETYPE,
|
||||
* TYPE, CLASS, STYLE, LANG, DIR, DECLARE, CLASSID, DATA, CODETYPE,
|
||||
* STANDBY, BORDER, SHAPES, NOSHADE, COMPACT, START, ACTION, METHOD,
|
||||
* ENCTYPE, CHECKED, MAXLENGTH, MULTIPLE, SELECTED, ROWS, COLS,
|
||||
* DUMMY, CELLSPACING, CELLPADDING, VALIGN, HALIGN, NOWRAP, ROWSPAN,
|
||||
* COLSPAN, PROMPT, HTTPEQUIV, CONTENT, LANGUAGE, VERSION, N,
|
||||
* FRAMEBORDER, MARGINWIDTH, MARGINHEIGHT, SCROLLING, NORESIZE,
|
||||
* MEDIA, ENDTAG}).
|
||||
* If the given name does not represent one of the well-known attributes,
|
||||
* then <code>null</code> will be returned.
|
||||
*
|
||||
* @param attName the <code>String</code> requested
|
||||
* @return the <code>Attribute</code> corresponding to <code>attName</code>
|
||||
*/
|
||||
public static Attribute getAttributeKey(String attName) {
|
||||
Attribute a = attHashtable.get(attName);
|
||||
if (a == null) {
|
||||
return null;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
||||
4201
jdkSrc/jdk8/javax/swing/text/html/HTMLDocument.java
Normal file
4201
jdkSrc/jdk8/javax/swing/text/html/HTMLDocument.java
Normal file
File diff suppressed because it is too large
Load Diff
2291
jdkSrc/jdk8/javax/swing/text/html/HTMLEditorKit.java
Normal file
2291
jdkSrc/jdk8/javax/swing/text/html/HTMLEditorKit.java
Normal file
File diff suppressed because it is too large
Load Diff
134
jdkSrc/jdk8/javax/swing/text/html/HTMLFrameHyperlinkEvent.java
Normal file
134
jdkSrc/jdk8/javax/swing/text/html/HTMLFrameHyperlinkEvent.java
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.awt.event.InputEvent;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* HTMLFrameHyperlinkEvent is used to notify interested
|
||||
* parties that link was activated in a frame.
|
||||
*
|
||||
* @author Sunita Mani
|
||||
*/
|
||||
|
||||
public class HTMLFrameHyperlinkEvent extends HyperlinkEvent {
|
||||
|
||||
/**
|
||||
* Creates a new object representing a html frame
|
||||
* hypertext link event.
|
||||
*
|
||||
* @param source the object responsible for the event
|
||||
* @param type the event type
|
||||
* @param targetURL the affected URL
|
||||
* @param targetFrame the Frame to display the document in
|
||||
*/
|
||||
public HTMLFrameHyperlinkEvent(Object source, EventType type, URL targetURL,
|
||||
String targetFrame) {
|
||||
super(source, type, targetURL);
|
||||
this.targetFrame = targetFrame;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new object representing a hypertext link event.
|
||||
*
|
||||
* @param source the object responsible for the event
|
||||
* @param type the event type
|
||||
* @param targetURL the affected URL
|
||||
* @param desc a description
|
||||
* @param targetFrame the Frame to display the document in
|
||||
*/
|
||||
public HTMLFrameHyperlinkEvent(Object source, EventType type, URL targetURL, String desc,
|
||||
String targetFrame) {
|
||||
super(source, type, targetURL, desc);
|
||||
this.targetFrame = targetFrame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new object representing a hypertext link event.
|
||||
*
|
||||
* @param source the object responsible for the event
|
||||
* @param type the event type
|
||||
* @param targetURL the affected URL
|
||||
* @param sourceElement the element that corresponds to the source
|
||||
* of the event
|
||||
* @param targetFrame the Frame to display the document in
|
||||
*/
|
||||
public HTMLFrameHyperlinkEvent(Object source, EventType type, URL targetURL,
|
||||
Element sourceElement, String targetFrame) {
|
||||
super(source, type, targetURL, null, sourceElement);
|
||||
this.targetFrame = targetFrame;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new object representing a hypertext link event.
|
||||
*
|
||||
* @param source the object responsible for the event
|
||||
* @param type the event type
|
||||
* @param targetURL the affected URL
|
||||
* @param desc a description
|
||||
* @param sourceElement the element that corresponds to the source
|
||||
* of the event
|
||||
* @param targetFrame the Frame to display the document in
|
||||
*/
|
||||
public HTMLFrameHyperlinkEvent(Object source, EventType type, URL targetURL, String desc,
|
||||
Element sourceElement, String targetFrame) {
|
||||
super(source, type, targetURL, desc, sourceElement);
|
||||
this.targetFrame = targetFrame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new object representing a hypertext link event.
|
||||
*
|
||||
* @param source the object responsible for the event
|
||||
* @param type the event type
|
||||
* @param targetURL the affected URL
|
||||
* @param desc a description
|
||||
* @param sourceElement the element that corresponds to the source
|
||||
* of the event
|
||||
* @param inputEvent InputEvent that triggered the hyperlink event
|
||||
* @param targetFrame the Frame to display the document in
|
||||
* @since 1.7
|
||||
*/
|
||||
public HTMLFrameHyperlinkEvent(Object source, EventType type, URL targetURL,
|
||||
String desc, Element sourceElement,
|
||||
InputEvent inputEvent, String targetFrame) {
|
||||
super(source, type, targetURL, desc, sourceElement, inputEvent);
|
||||
this.targetFrame = targetFrame;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the target for the link.
|
||||
*/
|
||||
public String getTarget() {
|
||||
return targetFrame;
|
||||
}
|
||||
|
||||
private String targetFrame;
|
||||
}
|
||||
1273
jdkSrc/jdk8/javax/swing/text/html/HTMLWriter.java
Normal file
1273
jdkSrc/jdk8/javax/swing/text/html/HTMLWriter.java
Normal file
File diff suppressed because it is too large
Load Diff
361
jdkSrc/jdk8/javax/swing/text/html/HiddenTagView.java
Normal file
361
jdkSrc/jdk8/javax/swing/text/html/HiddenTagView.java
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.*;
|
||||
import javax.swing.event.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* HiddenTagView subclasses EditableView to contain a JTextField showing
|
||||
* the element name. When the textfield is edited the element name is
|
||||
* reset. As this inherits from EditableView if the JTextComponent is
|
||||
* not editable, the textfield will not be visible.
|
||||
*
|
||||
* @author Scott Violet
|
||||
*/
|
||||
class HiddenTagView extends EditableView implements DocumentListener {
|
||||
HiddenTagView(Element e) {
|
||||
super(e);
|
||||
yAlign = 1;
|
||||
}
|
||||
|
||||
protected Component createComponent() {
|
||||
JTextField tf = new JTextField(getElement().getName());
|
||||
Document doc = getDocument();
|
||||
Font font;
|
||||
if (doc instanceof StyledDocument) {
|
||||
font = ((StyledDocument)doc).getFont(getAttributes());
|
||||
tf.setFont(font);
|
||||
}
|
||||
else {
|
||||
font = tf.getFont();
|
||||
}
|
||||
tf.getDocument().addDocumentListener(this);
|
||||
updateYAlign(font);
|
||||
|
||||
// Create a panel to wrap the textfield so that the textfields
|
||||
// laf border shows through.
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.setBackground(null);
|
||||
if (isEndTag()) {
|
||||
panel.setBorder(EndBorder);
|
||||
}
|
||||
else {
|
||||
panel.setBorder(StartBorder);
|
||||
}
|
||||
panel.add(tf);
|
||||
return panel;
|
||||
}
|
||||
|
||||
public float getAlignment(int axis) {
|
||||
if (axis == View.Y_AXIS) {
|
||||
return yAlign;
|
||||
}
|
||||
return 0.5f;
|
||||
}
|
||||
|
||||
public float getMinimumSpan(int axis) {
|
||||
if (axis == View.X_AXIS && isVisible()) {
|
||||
// Default to preferred.
|
||||
return Math.max(30, super.getPreferredSpan(axis));
|
||||
}
|
||||
return super.getMinimumSpan(axis);
|
||||
}
|
||||
|
||||
public float getPreferredSpan(int axis) {
|
||||
if (axis == View.X_AXIS && isVisible()) {
|
||||
return Math.max(30, super.getPreferredSpan(axis));
|
||||
}
|
||||
return super.getPreferredSpan(axis);
|
||||
}
|
||||
|
||||
public float getMaximumSpan(int axis) {
|
||||
if (axis == View.X_AXIS && isVisible()) {
|
||||
// Default to preferred.
|
||||
return Math.max(30, super.getMaximumSpan(axis));
|
||||
}
|
||||
return super.getMaximumSpan(axis);
|
||||
}
|
||||
|
||||
// DocumentListener methods
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
updateModelFromText();
|
||||
}
|
||||
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
updateModelFromText();
|
||||
}
|
||||
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
updateModelFromText();
|
||||
}
|
||||
|
||||
// View method
|
||||
public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
|
||||
if (!isSettingAttributes) {
|
||||
setTextFromModel();
|
||||
}
|
||||
}
|
||||
|
||||
// local methods
|
||||
|
||||
void updateYAlign(Font font) {
|
||||
Container c = getContainer();
|
||||
FontMetrics fm = (c != null) ? c.getFontMetrics(font) :
|
||||
Toolkit.getDefaultToolkit().getFontMetrics(font);
|
||||
float h = fm.getHeight();
|
||||
float d = fm.getDescent();
|
||||
yAlign = (h > 0) ? (h - d) / h : 0;
|
||||
}
|
||||
|
||||
void resetBorder() {
|
||||
Component comp = getComponent();
|
||||
|
||||
if (comp != null) {
|
||||
if (isEndTag()) {
|
||||
((JPanel)comp).setBorder(EndBorder);
|
||||
}
|
||||
else {
|
||||
((JPanel)comp).setBorder(StartBorder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This resets the text on the text component we created to match
|
||||
* that of the AttributeSet for the Element we represent.
|
||||
* <p>If this is invoked on the event dispatching thread, this
|
||||
* directly invokes <code>_setTextFromModel</code>, otherwise
|
||||
* <code>SwingUtilities.invokeLater</code> is used to schedule execution
|
||||
* of <code>_setTextFromModel</code>.
|
||||
*/
|
||||
void setTextFromModel() {
|
||||
if (SwingUtilities.isEventDispatchThread()) {
|
||||
_setTextFromModel();
|
||||
}
|
||||
else {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
_setTextFromModel();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This resets the text on the text component we created to match
|
||||
* that of the AttributeSet for the Element we represent.
|
||||
*/
|
||||
void _setTextFromModel() {
|
||||
Document doc = getDocument();
|
||||
try {
|
||||
isSettingAttributes = true;
|
||||
if (doc instanceof AbstractDocument) {
|
||||
((AbstractDocument)doc).readLock();
|
||||
}
|
||||
JTextComponent text = getTextComponent();
|
||||
if (text != null) {
|
||||
text.setText(getRepresentedText());
|
||||
resetBorder();
|
||||
Container host = getContainer();
|
||||
if (host != null) {
|
||||
preferenceChanged(this, true, true);
|
||||
host.repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
isSettingAttributes = false;
|
||||
if (doc instanceof AbstractDocument) {
|
||||
((AbstractDocument)doc).readUnlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This copies the text from the text component we've created
|
||||
* to the Element's AttributeSet we represent.
|
||||
* <p>If this is invoked on the event dispatching thread, this
|
||||
* directly invokes <code>_updateModelFromText</code>, otherwise
|
||||
* <code>SwingUtilities.invokeLater</code> is used to schedule execution
|
||||
* of <code>_updateModelFromText</code>.
|
||||
*/
|
||||
void updateModelFromText() {
|
||||
if (!isSettingAttributes) {
|
||||
if (SwingUtilities.isEventDispatchThread()) {
|
||||
_updateModelFromText();
|
||||
}
|
||||
else {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
_updateModelFromText();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This copies the text from the text component we've created
|
||||
* to the Element's AttributeSet we represent.
|
||||
*/
|
||||
void _updateModelFromText() {
|
||||
Document doc = getDocument();
|
||||
Object name = getElement().getAttributes().getAttribute
|
||||
(StyleConstants.NameAttribute);
|
||||
if ((name instanceof HTML.UnknownTag) &&
|
||||
(doc instanceof StyledDocument)) {
|
||||
SimpleAttributeSet sas = new SimpleAttributeSet();
|
||||
JTextComponent textComponent = getTextComponent();
|
||||
if (textComponent != null) {
|
||||
String text = textComponent.getText();
|
||||
isSettingAttributes = true;
|
||||
try {
|
||||
sas.addAttribute(StyleConstants.NameAttribute,
|
||||
new HTML.UnknownTag(text));
|
||||
((StyledDocument)doc).setCharacterAttributes
|
||||
(getStartOffset(), getEndOffset() -
|
||||
getStartOffset(), sas, false);
|
||||
}
|
||||
finally {
|
||||
isSettingAttributes = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JTextComponent getTextComponent() {
|
||||
Component comp = getComponent();
|
||||
|
||||
return (comp == null) ? null : (JTextComponent)((Container)comp).
|
||||
getComponent(0);
|
||||
}
|
||||
|
||||
String getRepresentedText() {
|
||||
String retValue = getElement().getName();
|
||||
return (retValue == null) ? "" : retValue;
|
||||
}
|
||||
|
||||
boolean isEndTag() {
|
||||
AttributeSet as = getElement().getAttributes();
|
||||
if (as != null) {
|
||||
Object end = as.getAttribute(HTML.Attribute.ENDTAG);
|
||||
if (end != null && (end instanceof String) &&
|
||||
((String)end).equals("true")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Alignment along the y axis, based on the font of the textfield. */
|
||||
float yAlign;
|
||||
/** Set to true when setting attributes. */
|
||||
boolean isSettingAttributes;
|
||||
|
||||
|
||||
// Following are for Borders that used for Unknown tags and comments.
|
||||
//
|
||||
// Border defines
|
||||
static final int circleR = 3;
|
||||
static final int circleD = circleR * 2;
|
||||
static final int tagSize = 6;
|
||||
static final int padding = 3;
|
||||
static final Color UnknownTagBorderColor = Color.black;
|
||||
static final Border StartBorder = new StartTagBorder();
|
||||
static final Border EndBorder = new EndTagBorder();
|
||||
|
||||
|
||||
static class StartTagBorder implements Border, Serializable {
|
||||
public void paintBorder(Component c, Graphics g, int x, int y,
|
||||
int width, int height) {
|
||||
g.setColor(UnknownTagBorderColor);
|
||||
x += padding;
|
||||
width -= (padding * 2);
|
||||
g.drawLine(x, y + circleR,
|
||||
x, y + height - circleR);
|
||||
g.drawArc(x, y + height - circleD - 1,
|
||||
circleD, circleD, 180, 90);
|
||||
g.drawArc(x, y, circleD, circleD, 90, 90);
|
||||
g.drawLine(x + circleR, y, x + width - tagSize, y);
|
||||
g.drawLine(x + circleR, y + height - 1,
|
||||
x + width - tagSize, y + height - 1);
|
||||
|
||||
g.drawLine(x + width - tagSize, y,
|
||||
x + width - 1, y + height / 2);
|
||||
g.drawLine(x + width - tagSize, y + height,
|
||||
x + width - 1, y + height / 2);
|
||||
}
|
||||
|
||||
public Insets getBorderInsets(Component c) {
|
||||
return new Insets(2, 2 + padding, 2, tagSize + 2 + padding);
|
||||
}
|
||||
|
||||
public boolean isBorderOpaque() {
|
||||
return false;
|
||||
}
|
||||
} // End of class HiddenTagView.StartTagBorder
|
||||
|
||||
|
||||
static class EndTagBorder implements Border, Serializable {
|
||||
public void paintBorder(Component c, Graphics g, int x, int y,
|
||||
int width, int height) {
|
||||
g.setColor(UnknownTagBorderColor);
|
||||
x += padding;
|
||||
width -= (padding * 2);
|
||||
g.drawLine(x + width - 1, y + circleR,
|
||||
x + width - 1, y + height - circleR);
|
||||
g.drawArc(x + width - circleD - 1, y + height - circleD - 1,
|
||||
circleD, circleD, 270, 90);
|
||||
g.drawArc(x + width - circleD - 1, y, circleD, circleD, 0, 90);
|
||||
g.drawLine(x + tagSize, y, x + width - circleR, y);
|
||||
g.drawLine(x + tagSize, y + height - 1,
|
||||
x + width - circleR, y + height - 1);
|
||||
|
||||
g.drawLine(x + tagSize, y,
|
||||
x, y + height / 2);
|
||||
g.drawLine(x + tagSize, y + height,
|
||||
x, y + height / 2);
|
||||
}
|
||||
|
||||
public Insets getBorderInsets(Component c) {
|
||||
return new Insets(2, tagSize + 2 + padding, 2, 2 + padding);
|
||||
}
|
||||
|
||||
public boolean isBorderOpaque() {
|
||||
return false;
|
||||
}
|
||||
} // End of class HiddenTagView.EndTagBorder
|
||||
|
||||
|
||||
} // End of HiddenTagView
|
||||
1069
jdkSrc/jdk8/javax/swing/text/html/ImageView.java
Normal file
1069
jdkSrc/jdk8/javax/swing/text/html/ImageView.java
Normal file
File diff suppressed because it is too large
Load Diff
225
jdkSrc/jdk8/javax/swing/text/html/InlineView.java
Normal file
225
jdkSrc/jdk8/javax/swing/text/html/InlineView.java
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.awt.*;
|
||||
import java.text.BreakIterator;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.text.*;
|
||||
|
||||
/**
|
||||
* Displays the <dfn>inline element</dfn> styles
|
||||
* based upon css attributes.
|
||||
*
|
||||
* @author Timothy Prinzing
|
||||
*/
|
||||
public class InlineView extends LabelView {
|
||||
|
||||
/**
|
||||
* Constructs a new view wrapped on an element.
|
||||
*
|
||||
* @param elem the element
|
||||
*/
|
||||
public InlineView(Element elem) {
|
||||
super(elem);
|
||||
StyleSheet sheet = getStyleSheet();
|
||||
attr = sheet.getViewAttributes(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives notification that something was inserted into
|
||||
* the document in a location that this view is responsible for.
|
||||
* If either parameter is <code>null</code>, behavior of this method is
|
||||
* implementation dependent.
|
||||
*
|
||||
* @param e the change information from the associated document
|
||||
* @param a the current allocation of the view
|
||||
* @param f the factory to use to rebuild if the view has children
|
||||
* @since 1.5
|
||||
* @see View#insertUpdate
|
||||
*/
|
||||
public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
|
||||
super.insertUpdate(e, a, f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives notification that something was removed from the document
|
||||
* in a location that this view is responsible for.
|
||||
* If either parameter is <code>null</code>, behavior of this method is
|
||||
* implementation dependent.
|
||||
*
|
||||
* @param e the change information from the associated document
|
||||
* @param a the current allocation of the view
|
||||
* @param f the factory to use to rebuild if the view has children
|
||||
* @since 1.5
|
||||
* @see View#removeUpdate
|
||||
*/
|
||||
public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
|
||||
super.removeUpdate(e, a, f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives notification from the document that attributes were changed
|
||||
* in a location that this view is responsible for.
|
||||
*
|
||||
* @param e the change information from the associated document
|
||||
* @param a the current allocation of the view
|
||||
* @param f the factory to use to rebuild if the view has children
|
||||
* @see View#changedUpdate
|
||||
*/
|
||||
public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
|
||||
super.changedUpdate(e, a, f);
|
||||
StyleSheet sheet = getStyleSheet();
|
||||
attr = sheet.getViewAttributes(this);
|
||||
preferenceChanged(null, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the attributes to use when rendering. This is
|
||||
* implemented to multiplex the attributes specified in the
|
||||
* model with a StyleSheet.
|
||||
*/
|
||||
public AttributeSet getAttributes() {
|
||||
return attr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines how attractive a break opportunity in
|
||||
* this view is. This can be used for determining which
|
||||
* view is the most attractive to call <code>breakView</code>
|
||||
* on in the process of formatting. A view that represents
|
||||
* text that has whitespace in it might be more attractive
|
||||
* than a view that has no whitespace, for example. The
|
||||
* higher the weight, the more attractive the break. A
|
||||
* value equal to or lower than <code>BadBreakWeight</code>
|
||||
* should not be considered for a break. A value greater
|
||||
* than or equal to <code>ForcedBreakWeight</code> should
|
||||
* be broken.
|
||||
* <p>
|
||||
* This is implemented to provide the default behavior
|
||||
* of returning <code>BadBreakWeight</code> unless the length
|
||||
* is greater than the length of the view in which case the
|
||||
* entire view represents the fragment. Unless a view has
|
||||
* been written to support breaking behavior, it is not
|
||||
* attractive to try and break the view. An example of
|
||||
* a view that does support breaking is <code>LabelView</code>.
|
||||
* An example of a view that uses break weight is
|
||||
* <code>ParagraphView</code>.
|
||||
*
|
||||
* @param axis may be either View.X_AXIS or View.Y_AXIS
|
||||
* @param pos the potential location of the start of the
|
||||
* broken view >= 0. This may be useful for calculating tab
|
||||
* positions.
|
||||
* @param len specifies the relative length from <em>pos</em>
|
||||
* where a potential break is desired >= 0.
|
||||
* @return the weight, which should be a value between
|
||||
* ForcedBreakWeight and BadBreakWeight.
|
||||
* @see LabelView
|
||||
* @see ParagraphView
|
||||
* @see javax.swing.text.View#BadBreakWeight
|
||||
* @see javax.swing.text.View#GoodBreakWeight
|
||||
* @see javax.swing.text.View#ExcellentBreakWeight
|
||||
* @see javax.swing.text.View#ForcedBreakWeight
|
||||
*/
|
||||
public int getBreakWeight(int axis, float pos, float len) {
|
||||
if (nowrap) {
|
||||
return BadBreakWeight;
|
||||
}
|
||||
return super.getBreakWeight(axis, pos, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to break this view on the given axis. Refer to
|
||||
* {@link javax.swing.text.View#breakView} for a complete
|
||||
* description of this method.
|
||||
* <p>Behavior of this method is unspecified in case <code>axis</code>
|
||||
* is neither <code>View.X_AXIS</code> nor <code>View.Y_AXIS</code>, and
|
||||
* in case <code>offset</code>, <code>pos</code>, or <code>len</code>
|
||||
* is null.
|
||||
*
|
||||
* @param axis may be either <code>View.X_AXIS</code> or
|
||||
* <code>View.Y_AXIS</code>
|
||||
* @param offset the location in the document model
|
||||
* that a broken fragment would occupy >= 0. This
|
||||
* would be the starting offset of the fragment
|
||||
* returned
|
||||
* @param pos the position along the axis that the
|
||||
* broken view would occupy >= 0. This may be useful for
|
||||
* things like tab calculations
|
||||
* @param len specifies the distance along the axis
|
||||
* where a potential break is desired >= 0
|
||||
* @return the fragment of the view that represents the
|
||||
* given span.
|
||||
* @since 1.5
|
||||
* @see javax.swing.text.View#breakView
|
||||
*/
|
||||
public View breakView(int axis, int offset, float pos, float len) {
|
||||
return super.breakView(axis, offset, pos, len);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the cached properties from the attributes.
|
||||
*/
|
||||
protected void setPropertiesFromAttributes() {
|
||||
super.setPropertiesFromAttributes();
|
||||
AttributeSet a = getAttributes();
|
||||
Object decor = a.getAttribute(CSS.Attribute.TEXT_DECORATION);
|
||||
boolean u = (decor != null) ?
|
||||
(decor.toString().indexOf("underline") >= 0) : false;
|
||||
setUnderline(u);
|
||||
boolean s = (decor != null) ?
|
||||
(decor.toString().indexOf("line-through") >= 0) : false;
|
||||
setStrikeThrough(s);
|
||||
Object vAlign = a.getAttribute(CSS.Attribute.VERTICAL_ALIGN);
|
||||
s = (vAlign != null) ? (vAlign.toString().indexOf("sup") >= 0) : false;
|
||||
setSuperscript(s);
|
||||
s = (vAlign != null) ? (vAlign.toString().indexOf("sub") >= 0) : false;
|
||||
setSubscript(s);
|
||||
|
||||
Object whitespace = a.getAttribute(CSS.Attribute.WHITE_SPACE);
|
||||
if ((whitespace != null) && whitespace.equals("nowrap")) {
|
||||
nowrap = true;
|
||||
} else {
|
||||
nowrap = false;
|
||||
}
|
||||
|
||||
HTMLDocument doc = (HTMLDocument)getDocument();
|
||||
// fetches background color from stylesheet if specified
|
||||
Color bg = doc.getBackground(a);
|
||||
if (bg != null) {
|
||||
setBackground(bg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected StyleSheet getStyleSheet() {
|
||||
HTMLDocument doc = (HTMLDocument) getDocument();
|
||||
return doc.getStyleSheet();
|
||||
}
|
||||
|
||||
private boolean nowrap;
|
||||
private AttributeSet attr;
|
||||
}
|
||||
114
jdkSrc/jdk8/javax/swing/text/html/IsindexView.java
Normal file
114
jdkSrc/jdk8/javax/swing/text/html/IsindexView.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.net.URLEncoder;
|
||||
import java.net.MalformedURLException;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.*;
|
||||
|
||||
|
||||
/**
|
||||
* A view that supports the <ISINDEX< tag. This is implemented
|
||||
* as a JPanel that contains
|
||||
*
|
||||
* @author Sunita Mani
|
||||
*/
|
||||
|
||||
class IsindexView extends ComponentView implements ActionListener {
|
||||
|
||||
JTextField textField;
|
||||
|
||||
/**
|
||||
* Creates an IsindexView
|
||||
*/
|
||||
public IsindexView(Element elem) {
|
||||
super(elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the components necessary to to implement
|
||||
* this view. The component returned is a <code>JPanel</code>,
|
||||
* that contains the PROMPT to the left and <code>JTextField</code>
|
||||
* to the right.
|
||||
*/
|
||||
public Component createComponent() {
|
||||
AttributeSet attr = getElement().getAttributes();
|
||||
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.setBackground(null);
|
||||
|
||||
String prompt = (String)attr.getAttribute(HTML.Attribute.PROMPT);
|
||||
if (prompt == null) {
|
||||
prompt = UIManager.getString("IsindexView.prompt");
|
||||
}
|
||||
JLabel label = new JLabel(prompt);
|
||||
|
||||
textField = new JTextField();
|
||||
textField.addActionListener(this);
|
||||
panel.add(label, BorderLayout.WEST);
|
||||
panel.add(textField, BorderLayout.CENTER);
|
||||
panel.setAlignmentY(1.0f);
|
||||
panel.setOpaque(false);
|
||||
return panel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for processing the ActionEvent.
|
||||
* In this case this is hitting enter/return
|
||||
* in the text field. This will construct the
|
||||
* URL from the base URL of the document.
|
||||
* To the URL is appended a '?' followed by the
|
||||
* contents of the JTextField. The search
|
||||
* contents are URLEncoded.
|
||||
*/
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
|
||||
String data = textField.getText();
|
||||
if (data != null) {
|
||||
data = URLEncoder.encode(data);
|
||||
}
|
||||
|
||||
|
||||
AttributeSet attr = getElement().getAttributes();
|
||||
HTMLDocument hdoc = (HTMLDocument)getElement().getDocument();
|
||||
|
||||
String action = (String) attr.getAttribute(HTML.Attribute.ACTION);
|
||||
if (action == null) {
|
||||
action = hdoc.getBase().toString();
|
||||
}
|
||||
try {
|
||||
URL url = new URL(action+"?"+data);
|
||||
JEditorPane pane = (JEditorPane)getContainer();
|
||||
pane.setPage(url);
|
||||
} catch (MalformedURLException e1) {
|
||||
} catch (IOException e2) {
|
||||
}
|
||||
}
|
||||
}
|
||||
186
jdkSrc/jdk8/javax/swing/text/html/LineView.java
Normal file
186
jdkSrc/jdk8/javax/swing/text/html/LineView.java
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.awt.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.text.*;
|
||||
|
||||
/**
|
||||
* A view implementation to display an unwrapped
|
||||
* preformatted line.<p>
|
||||
* This subclasses ParagraphView, but this really only contains one
|
||||
* Row of text.
|
||||
*
|
||||
* @author Timothy Prinzing
|
||||
*/
|
||||
class LineView extends ParagraphView {
|
||||
/** Last place painted at. */
|
||||
int tabBase;
|
||||
|
||||
/**
|
||||
* Creates a LineView object.
|
||||
*
|
||||
* @param elem the element to wrap in a view
|
||||
*/
|
||||
public LineView(Element elem) {
|
||||
super(elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Preformatted lines are not suppressed if they
|
||||
* have only whitespace, so they are always visible.
|
||||
*/
|
||||
public boolean isVisible() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the minimum span for this view along an
|
||||
* axis. The preformatted line should refuse to be
|
||||
* sized less than the preferred size.
|
||||
*
|
||||
* @param axis may be either <code>View.X_AXIS</code> or
|
||||
* <code>View.Y_AXIS</code>
|
||||
* @return the minimum span the view can be rendered into
|
||||
* @see View#getPreferredSpan
|
||||
*/
|
||||
public float getMinimumSpan(int axis) {
|
||||
return getPreferredSpan(axis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the resize weight for the specified axis.
|
||||
*
|
||||
* @param axis may be either X_AXIS or Y_AXIS
|
||||
* @return the weight
|
||||
*/
|
||||
public int getResizeWeight(int axis) {
|
||||
switch (axis) {
|
||||
case View.X_AXIS:
|
||||
return 1;
|
||||
case View.Y_AXIS:
|
||||
return 0;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid axis: " + axis);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the alignment for an axis.
|
||||
*
|
||||
* @param axis may be either X_AXIS or Y_AXIS
|
||||
* @return the alignment
|
||||
*/
|
||||
public float getAlignment(int axis) {
|
||||
if (axis == View.X_AXIS) {
|
||||
return 0;
|
||||
}
|
||||
return super.getAlignment(axis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lays out the children. If the layout span has changed,
|
||||
* the rows are rebuilt. The superclass functionality
|
||||
* is called after checking and possibly rebuilding the
|
||||
* rows. If the height has changed, the
|
||||
* <code>preferenceChanged</code> method is called
|
||||
* on the parent since the vertical preference is
|
||||
* rigid.
|
||||
*
|
||||
* @param width the width to lay out against >= 0. This is
|
||||
* the width inside of the inset area.
|
||||
* @param height the height to lay out against >= 0 (not used
|
||||
* by paragraph, but used by the superclass). This
|
||||
* is the height inside of the inset area.
|
||||
*/
|
||||
protected void layout(int width, int height) {
|
||||
super.layout(Integer.MAX_VALUE - 1, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next tab stop position given a reference position.
|
||||
* This view implements the tab coordinate system, and calls
|
||||
* <code>getTabbedSpan</code> on the logical children in the process
|
||||
* of layout to determine the desired span of the children. The
|
||||
* logical children can delegate their tab expansion upward to
|
||||
* the paragraph which knows how to expand tabs.
|
||||
* <code>LabelView</code> is an example of a view that delegates
|
||||
* its tab expansion needs upward to the paragraph.
|
||||
* <p>
|
||||
* This is implemented to try and locate a <code>TabSet</code>
|
||||
* in the paragraph element's attribute set. If one can be
|
||||
* found, its settings will be used, otherwise a default expansion
|
||||
* will be provided. The base location for for tab expansion
|
||||
* is the left inset from the paragraphs most recent allocation
|
||||
* (which is what the layout of the children is based upon).
|
||||
*
|
||||
* @param x the X reference position
|
||||
* @param tabOffset the position within the text stream
|
||||
* that the tab occurred at >= 0.
|
||||
* @return the trailing end of the tab expansion >= 0
|
||||
* @see TabSet
|
||||
* @see TabStop
|
||||
* @see LabelView
|
||||
*/
|
||||
public float nextTabStop(float x, int tabOffset) {
|
||||
// If the text isn't left justified, offset by 10 pixels!
|
||||
if (getTabSet() == null &&
|
||||
StyleConstants.getAlignment(getAttributes()) ==
|
||||
StyleConstants.ALIGN_LEFT) {
|
||||
return getPreTab(x, tabOffset);
|
||||
}
|
||||
return super.nextTabStop(x, tabOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the location for the tab.
|
||||
*/
|
||||
protected float getPreTab(float x, int tabOffset) {
|
||||
Document d = getDocument();
|
||||
View v = getViewAtPosition(tabOffset, null);
|
||||
if ((d instanceof StyledDocument) && v != null) {
|
||||
// Assume f is fixed point.
|
||||
Font f = ((StyledDocument)d).getFont(v.getAttributes());
|
||||
Container c = getContainer();
|
||||
FontMetrics fm = (c != null) ? c.getFontMetrics(f) :
|
||||
Toolkit.getDefaultToolkit().getFontMetrics(f);
|
||||
int width = getCharactersPerTab() * fm.charWidth('W');
|
||||
int tb = (int)getTabBase();
|
||||
return (float)((((int)x - tb) / width + 1) * width + tb);
|
||||
}
|
||||
return 10.0f + x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return number of characters per tab, 8.
|
||||
*/
|
||||
protected int getCharactersPerTab() {
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
122
jdkSrc/jdk8/javax/swing/text/html/ListView.java
Normal file
122
jdkSrc/jdk8/javax/swing/text/html/ListView.java
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 1999, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.awt.*;
|
||||
import javax.swing.text.*;
|
||||
|
||||
/**
|
||||
* A view implementation to display an html list
|
||||
*
|
||||
* @author Timothy Prinzing
|
||||
*/
|
||||
public class ListView extends BlockView {
|
||||
|
||||
/**
|
||||
* Creates a new view that represents a list element.
|
||||
*
|
||||
* @param elem the element to create a view for
|
||||
*/
|
||||
public ListView(Element elem) {
|
||||
super(elem, View.Y_AXIS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the desired shape of the list.
|
||||
*
|
||||
* @return the desired span
|
||||
* @see View#getPreferredSpan
|
||||
*/
|
||||
public float getAlignment(int axis) {
|
||||
switch (axis) {
|
||||
case View.X_AXIS:
|
||||
return 0.5f;
|
||||
case View.Y_AXIS:
|
||||
return 0.5f;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid axis: " + axis);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders using the given rendering surface and area on that
|
||||
* surface.
|
||||
*
|
||||
* @param g the rendering surface to use
|
||||
* @param allocation the allocated region to render into
|
||||
* @see View#paint
|
||||
*/
|
||||
public void paint(Graphics g, Shape allocation) {
|
||||
super.paint(g, allocation);
|
||||
Rectangle alloc = allocation.getBounds();
|
||||
Rectangle clip = g.getClipBounds();
|
||||
// Since listPainter paints in the insets we have to check for the
|
||||
// case where the child is not painted because the paint region is
|
||||
// to the left of the child. This assumes the ListPainter paints in
|
||||
// the left margin.
|
||||
if ((clip.x + clip.width) < (alloc.x + getLeftInset())) {
|
||||
Rectangle childRect = alloc;
|
||||
alloc = getInsideAllocation(allocation);
|
||||
int n = getViewCount();
|
||||
int endY = clip.y + clip.height;
|
||||
for (int i = 0; i < n; i++) {
|
||||
childRect.setBounds(alloc);
|
||||
childAllocation(i, childRect);
|
||||
if (childRect.y < endY) {
|
||||
if ((childRect.y + childRect.height) >= clip.y) {
|
||||
listPainter.paint(g, childRect.x, childRect.y,
|
||||
childRect.width, childRect.height,
|
||||
this, i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints one of the children; called by paint(). By default
|
||||
* that is all it does, but a subclass can use this to paint
|
||||
* things relative to the child.
|
||||
*
|
||||
* @param g the graphics context
|
||||
* @param alloc the allocated region to render the child into
|
||||
* @param index the index of the child
|
||||
*/
|
||||
protected void paintChild(Graphics g, Rectangle alloc, int index) {
|
||||
listPainter.paint(g, alloc.x, alloc.y, alloc.width, alloc.height, this, index);
|
||||
super.paintChild(g, alloc, index);
|
||||
}
|
||||
|
||||
protected void setPropertiesFromAttributes() {
|
||||
super.setPropertiesFromAttributes();
|
||||
listPainter = getStyleSheet().getListPainter(getAttributes());
|
||||
}
|
||||
|
||||
private StyleSheet.ListPainter listPainter;
|
||||
}
|
||||
503
jdkSrc/jdk8/javax/swing/text/html/Map.java
Normal file
503
jdkSrc/jdk8/javax/swing/text/html/Map.java
Normal file
@@ -0,0 +1,503 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.awt.Polygon;
|
||||
import java.io.Serializable;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Vector;
|
||||
import javax.swing.text.AttributeSet;
|
||||
|
||||
/**
|
||||
* Map is used to represent a map element that is part of an HTML document.
|
||||
* Once a Map has been created, and any number of areas have been added,
|
||||
* you can test if a point falls inside the map via the contains method.
|
||||
*
|
||||
* @author Scott Violet
|
||||
*/
|
||||
class Map implements Serializable {
|
||||
/** Name of the Map. */
|
||||
private String name;
|
||||
/** An array of AttributeSets. */
|
||||
private Vector<AttributeSet> areaAttributes;
|
||||
/** An array of RegionContainments, will slowly grow to match the
|
||||
* length of areaAttributes as needed. */
|
||||
private Vector<RegionContainment> areas;
|
||||
|
||||
public Map() {
|
||||
}
|
||||
|
||||
public Map(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the Map.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a region of the Map, based on the passed in AttributeSet.
|
||||
*/
|
||||
public void addArea(AttributeSet as) {
|
||||
if (as == null) {
|
||||
return;
|
||||
}
|
||||
if (areaAttributes == null) {
|
||||
areaAttributes = new Vector<AttributeSet>(2);
|
||||
}
|
||||
areaAttributes.addElement(as.copyAttributes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the previously created area.
|
||||
*/
|
||||
public void removeArea(AttributeSet as) {
|
||||
if (as != null && areaAttributes != null) {
|
||||
int numAreas = (areas != null) ? areas.size() : 0;
|
||||
for (int counter = areaAttributes.size() - 1; counter >= 0;
|
||||
counter--) {
|
||||
if (areaAttributes.elementAt(counter).isEqual(as)){
|
||||
areaAttributes.removeElementAt(counter);
|
||||
if (counter < numAreas) {
|
||||
areas.removeElementAt(counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the AttributeSets representing the differet areas of the Map.
|
||||
*/
|
||||
public AttributeSet[] getAreas() {
|
||||
int numAttributes = (areaAttributes != null) ? areaAttributes.size() :
|
||||
0;
|
||||
if (numAttributes != 0) {
|
||||
AttributeSet[] retValue = new AttributeSet[numAttributes];
|
||||
|
||||
areaAttributes.copyInto(retValue);
|
||||
return retValue;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the AttributeSet that contains the passed in location,
|
||||
* <code>x</code>, <code>y</code>. <code>width</code>, <code>height</code>
|
||||
* gives the size of the region the map is defined over. If a matching
|
||||
* area is found, the AttribueSet for it is returned.
|
||||
*/
|
||||
public AttributeSet getArea(int x, int y, int width, int height) {
|
||||
int numAttributes = (areaAttributes != null) ?
|
||||
areaAttributes.size() : 0;
|
||||
|
||||
if (numAttributes > 0) {
|
||||
int numAreas = (areas != null) ? areas.size() : 0;
|
||||
|
||||
if (areas == null) {
|
||||
areas = new Vector<RegionContainment>(numAttributes);
|
||||
}
|
||||
for (int counter = 0; counter < numAttributes; counter++) {
|
||||
if (counter >= numAreas) {
|
||||
areas.addElement(createRegionContainment
|
||||
(areaAttributes.elementAt(counter)));
|
||||
}
|
||||
RegionContainment rc = areas.elementAt(counter);
|
||||
if (rc != null && rc.contains(x, y, width, height)) {
|
||||
return areaAttributes.elementAt(counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns an instance of RegionContainment that can be
|
||||
* used to test if a particular point lies inside a region.
|
||||
*/
|
||||
protected RegionContainment createRegionContainment
|
||||
(AttributeSet attributes) {
|
||||
Object shape = attributes.getAttribute(HTML.Attribute.SHAPE);
|
||||
|
||||
if (shape == null) {
|
||||
shape = "rect";
|
||||
}
|
||||
if (shape instanceof String) {
|
||||
String shapeString = ((String)shape).toLowerCase();
|
||||
RegionContainment rc = null;
|
||||
|
||||
try {
|
||||
if (shapeString.equals("rect")) {
|
||||
rc = new RectangleRegionContainment(attributes);
|
||||
}
|
||||
else if (shapeString.equals("circle")) {
|
||||
rc = new CircleRegionContainment(attributes);
|
||||
}
|
||||
else if (shapeString.equals("poly")) {
|
||||
rc = new PolygonRegionContainment(attributes);
|
||||
}
|
||||
else if (shapeString.equals("default")) {
|
||||
rc = DefaultRegionContainment.sharedInstance();
|
||||
}
|
||||
} catch (RuntimeException re) {
|
||||
// Something wrong with attributes.
|
||||
rc = null;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns an array of integers from the String
|
||||
* <code>stringCoords</code>. If one of the values represents a
|
||||
* % the returned value with be negative. If a parse error results
|
||||
* from trying to parse one of the numbers null is returned.
|
||||
*/
|
||||
static protected int[] extractCoords(Object stringCoords) {
|
||||
if (stringCoords == null || !(stringCoords instanceof String)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
StringTokenizer st = new StringTokenizer((String)stringCoords,
|
||||
", \t\n\r");
|
||||
int[] retValue = null;
|
||||
int numCoords = 0;
|
||||
|
||||
while(st.hasMoreElements()) {
|
||||
String token = st.nextToken();
|
||||
int scale;
|
||||
|
||||
if (token.endsWith("%")) {
|
||||
scale = -1;
|
||||
token = token.substring(0, token.length() - 1);
|
||||
}
|
||||
else {
|
||||
scale = 1;
|
||||
}
|
||||
try {
|
||||
int intValue = Integer.parseInt(token);
|
||||
|
||||
if (retValue == null) {
|
||||
retValue = new int[4];
|
||||
}
|
||||
else if(numCoords == retValue.length) {
|
||||
int[] temp = new int[retValue.length * 2];
|
||||
|
||||
System.arraycopy(retValue, 0, temp, 0, retValue.length);
|
||||
retValue = temp;
|
||||
}
|
||||
retValue[numCoords++] = intValue * scale;
|
||||
} catch (NumberFormatException nfe) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (numCoords > 0 && numCoords != retValue.length) {
|
||||
int[] temp = new int[numCoords];
|
||||
|
||||
System.arraycopy(retValue, 0, temp, 0, numCoords);
|
||||
retValue = temp;
|
||||
}
|
||||
return retValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Defines the interface used for to check if a point is inside a
|
||||
* region.
|
||||
*/
|
||||
interface RegionContainment {
|
||||
/**
|
||||
* Returns true if the location <code>x</code>, <code>y</code>
|
||||
* falls inside the region defined in the receiver.
|
||||
* <code>width</code>, <code>height</code> is the size of
|
||||
* the enclosing region.
|
||||
*/
|
||||
public boolean contains(int x, int y, int width, int height);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Used to test for containment in a rectangular region.
|
||||
*/
|
||||
static class RectangleRegionContainment implements RegionContainment {
|
||||
/** Will be non-null if one of the values is a percent, and any value
|
||||
* that is non null indicates it is a percent
|
||||
* (order is x, y, width, height). */
|
||||
float[] percents;
|
||||
/** Last value of width passed in. */
|
||||
int lastWidth;
|
||||
/** Last value of height passed in. */
|
||||
int lastHeight;
|
||||
/** Top left. */
|
||||
int x0;
|
||||
int y0;
|
||||
/** Bottom right. */
|
||||
int x1;
|
||||
int y1;
|
||||
|
||||
public RectangleRegionContainment(AttributeSet as) {
|
||||
int[] coords = Map.extractCoords(as.getAttribute(HTML.
|
||||
Attribute.COORDS));
|
||||
|
||||
percents = null;
|
||||
if (coords == null || coords.length != 4) {
|
||||
throw new RuntimeException("Unable to parse rectangular area");
|
||||
}
|
||||
else {
|
||||
x0 = coords[0];
|
||||
y0 = coords[1];
|
||||
x1 = coords[2];
|
||||
y1 = coords[3];
|
||||
if (x0 < 0 || y0 < 0 || x1 < 0 || y1 < 0) {
|
||||
percents = new float[4];
|
||||
lastWidth = lastHeight = -1;
|
||||
for (int counter = 0; counter < 4; counter++) {
|
||||
if (coords[counter] < 0) {
|
||||
percents[counter] = Math.abs
|
||||
(coords[counter]) / 100.0f;
|
||||
}
|
||||
else {
|
||||
percents[counter] = -1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(int x, int y, int width, int height) {
|
||||
if (percents == null) {
|
||||
return contains(x, y);
|
||||
}
|
||||
if (lastWidth != width || lastHeight != height) {
|
||||
lastWidth = width;
|
||||
lastHeight = height;
|
||||
if (percents[0] != -1.0f) {
|
||||
x0 = (int)(percents[0] * width);
|
||||
}
|
||||
if (percents[1] != -1.0f) {
|
||||
y0 = (int)(percents[1] * height);
|
||||
}
|
||||
if (percents[2] != -1.0f) {
|
||||
x1 = (int)(percents[2] * width);
|
||||
}
|
||||
if (percents[3] != -1.0f) {
|
||||
y1 = (int)(percents[3] * height);
|
||||
}
|
||||
}
|
||||
return contains(x, y);
|
||||
}
|
||||
|
||||
public boolean contains(int x, int y) {
|
||||
return ((x >= x0 && x <= x1) &&
|
||||
(y >= y0 && y <= y1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Used to test for containment in a polygon region.
|
||||
*/
|
||||
static class PolygonRegionContainment extends Polygon implements
|
||||
RegionContainment {
|
||||
/** If any value is a percent there will be an entry here for the
|
||||
* percent value. Use percentIndex to find out the index for it. */
|
||||
float[] percentValues;
|
||||
int[] percentIndexs;
|
||||
/** Last value of width passed in. */
|
||||
int lastWidth;
|
||||
/** Last value of height passed in. */
|
||||
int lastHeight;
|
||||
|
||||
public PolygonRegionContainment(AttributeSet as) {
|
||||
int[] coords = Map.extractCoords(as.getAttribute(HTML.Attribute.
|
||||
COORDS));
|
||||
|
||||
if (coords == null || coords.length == 0 ||
|
||||
coords.length % 2 != 0) {
|
||||
throw new RuntimeException("Unable to parse polygon area");
|
||||
}
|
||||
else {
|
||||
int numPercents = 0;
|
||||
|
||||
lastWidth = lastHeight = -1;
|
||||
for (int counter = coords.length - 1; counter >= 0;
|
||||
counter--) {
|
||||
if (coords[counter] < 0) {
|
||||
numPercents++;
|
||||
}
|
||||
}
|
||||
|
||||
if (numPercents > 0) {
|
||||
percentIndexs = new int[numPercents];
|
||||
percentValues = new float[numPercents];
|
||||
for (int counter = coords.length - 1, pCounter = 0;
|
||||
counter >= 0; counter--) {
|
||||
if (coords[counter] < 0) {
|
||||
percentValues[pCounter] = coords[counter] /
|
||||
-100.0f;
|
||||
percentIndexs[pCounter] = counter;
|
||||
pCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
percentIndexs = null;
|
||||
percentValues = null;
|
||||
}
|
||||
npoints = coords.length / 2;
|
||||
xpoints = new int[npoints];
|
||||
ypoints = new int[npoints];
|
||||
|
||||
for (int counter = 0; counter < npoints; counter++) {
|
||||
xpoints[counter] = coords[counter + counter];
|
||||
ypoints[counter] = coords[counter + counter + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(int x, int y, int width, int height) {
|
||||
if (percentValues == null || (lastWidth == width &&
|
||||
lastHeight == height)) {
|
||||
return contains(x, y);
|
||||
}
|
||||
// Force the bounding box to be recalced.
|
||||
bounds = null;
|
||||
lastWidth = width;
|
||||
lastHeight = height;
|
||||
float fWidth = (float)width;
|
||||
float fHeight = (float)height;
|
||||
for (int counter = percentValues.length - 1; counter >= 0;
|
||||
counter--) {
|
||||
if (percentIndexs[counter] % 2 == 0) {
|
||||
// x
|
||||
xpoints[percentIndexs[counter] / 2] =
|
||||
(int)(percentValues[counter] * fWidth);
|
||||
}
|
||||
else {
|
||||
// y
|
||||
ypoints[percentIndexs[counter] / 2] =
|
||||
(int)(percentValues[counter] * fHeight);
|
||||
}
|
||||
}
|
||||
return contains(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Used to test for containment in a circular region.
|
||||
*/
|
||||
static class CircleRegionContainment implements RegionContainment {
|
||||
/** X origin of the circle. */
|
||||
int x;
|
||||
/** Y origin of the circle. */
|
||||
int y;
|
||||
/** Radius of the circle. */
|
||||
int radiusSquared;
|
||||
/** Non-null indicates one of the values represents a percent. */
|
||||
float[] percentValues;
|
||||
/** Last value of width passed in. */
|
||||
int lastWidth;
|
||||
/** Last value of height passed in. */
|
||||
int lastHeight;
|
||||
|
||||
public CircleRegionContainment(AttributeSet as) {
|
||||
int[] coords = Map.extractCoords(as.getAttribute(HTML.Attribute.
|
||||
COORDS));
|
||||
|
||||
if (coords == null || coords.length != 3) {
|
||||
throw new RuntimeException("Unable to parse circular area");
|
||||
}
|
||||
x = coords[0];
|
||||
y = coords[1];
|
||||
radiusSquared = coords[2] * coords[2];
|
||||
if (coords[0] < 0 || coords[1] < 0 || coords[2] < 0) {
|
||||
lastWidth = lastHeight = -1;
|
||||
percentValues = new float[3];
|
||||
for (int counter = 0; counter < 3; counter++) {
|
||||
if (coords[counter] < 0) {
|
||||
percentValues[counter] = coords[counter] /
|
||||
-100.0f;
|
||||
}
|
||||
else {
|
||||
percentValues[counter] = -1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
percentValues = null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(int x, int y, int width, int height) {
|
||||
if (percentValues != null && (lastWidth != width ||
|
||||
lastHeight != height)) {
|
||||
int newRad = Math.min(width, height) / 2;
|
||||
|
||||
lastWidth = width;
|
||||
lastHeight = height;
|
||||
if (percentValues[0] != -1.0f) {
|
||||
this.x = (int)(percentValues[0] * width);
|
||||
}
|
||||
if (percentValues[1] != -1.0f) {
|
||||
this.y = (int)(percentValues[1] * height);
|
||||
}
|
||||
if (percentValues[2] != -1.0f) {
|
||||
radiusSquared = (int)(percentValues[2] *
|
||||
Math.min(width, height));
|
||||
radiusSquared *= radiusSquared;
|
||||
}
|
||||
}
|
||||
return (((x - this.x) * (x - this.x) +
|
||||
(y - this.y) * (y - this.y)) <= radiusSquared);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An implementation that will return true if the x, y location is
|
||||
* inside a rectangle defined by origin 0, 0, and width equal to
|
||||
* width passed in, and height equal to height passed in.
|
||||
*/
|
||||
static class DefaultRegionContainment implements RegionContainment {
|
||||
/** A global shared instance. */
|
||||
static DefaultRegionContainment si = null;
|
||||
|
||||
public static DefaultRegionContainment sharedInstance() {
|
||||
if (si == null) {
|
||||
si = new DefaultRegionContainment();
|
||||
}
|
||||
return si;
|
||||
}
|
||||
|
||||
public boolean contains(int x, int y, int width, int height) {
|
||||
return (x <= width && x >= 0 && y >= 0 && y <= width);
|
||||
}
|
||||
}
|
||||
}
|
||||
726
jdkSrc/jdk8/javax/swing/text/html/MinimalHTMLWriter.java
Normal file
726
jdkSrc/jdk8/javax/swing/text/html/MinimalHTMLWriter.java
Normal file
@@ -0,0 +1,726 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.awt.Color;
|
||||
import javax.swing.text.*;
|
||||
|
||||
/**
|
||||
* MinimalHTMLWriter is a fallback writer used by the
|
||||
* HTMLEditorKit to write out HTML for a document that
|
||||
* is a not produced by the EditorKit.
|
||||
*
|
||||
* The format for the document is:
|
||||
* <pre>
|
||||
* <html>
|
||||
* <head>
|
||||
* <style>
|
||||
* <!-- list of named styles
|
||||
* p.normal {
|
||||
* font-family: SansSerif;
|
||||
* margin-height: 0;
|
||||
* font-size: 14
|
||||
* }
|
||||
* -->
|
||||
* </style>
|
||||
* </head>
|
||||
* <body>
|
||||
* <p style=normal>
|
||||
* <b>Bold, italic, and underline attributes
|
||||
* of the run are emitted as HTML tags.
|
||||
* The remaining attributes are emitted as
|
||||
* part of the style attribute of a <span> tag.
|
||||
* The syntax is similar to inline styles.</b>
|
||||
* </p>
|
||||
* </body>
|
||||
* </html>
|
||||
* </pre>
|
||||
*
|
||||
* @author Sunita Mani
|
||||
*/
|
||||
|
||||
public class MinimalHTMLWriter extends AbstractWriter {
|
||||
|
||||
/**
|
||||
* These static finals are used to
|
||||
* tweak and query the fontMask about which
|
||||
* of these tags need to be generated or
|
||||
* terminated.
|
||||
*/
|
||||
private static final int BOLD = 0x01;
|
||||
private static final int ITALIC = 0x02;
|
||||
private static final int UNDERLINE = 0x04;
|
||||
|
||||
// Used to map StyleConstants to CSS.
|
||||
private static final CSS css = new CSS();
|
||||
|
||||
private int fontMask = 0;
|
||||
|
||||
int startOffset = 0;
|
||||
int endOffset = 0;
|
||||
|
||||
/**
|
||||
* Stores the attributes of the previous run.
|
||||
* Used to compare with the current run's
|
||||
* attributeset. If identical, then a
|
||||
* <span> tag is not emitted.
|
||||
*/
|
||||
private AttributeSet fontAttributes;
|
||||
|
||||
/**
|
||||
* Maps from style name as held by the Document, to the archived
|
||||
* style name (style name written out). These may differ.
|
||||
*/
|
||||
private Hashtable<String, String> styleNameMapping;
|
||||
|
||||
/**
|
||||
* Creates a new MinimalHTMLWriter.
|
||||
*
|
||||
* @param w Writer
|
||||
* @param doc StyledDocument
|
||||
*
|
||||
*/
|
||||
public MinimalHTMLWriter(Writer w, StyledDocument doc) {
|
||||
super(w, doc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new MinimalHTMLWriter.
|
||||
*
|
||||
* @param w Writer
|
||||
* @param doc StyledDocument
|
||||
* @param pos The location in the document to fetch the
|
||||
* content.
|
||||
* @param len The amount to write out.
|
||||
*
|
||||
*/
|
||||
public MinimalHTMLWriter(Writer w, StyledDocument doc, int pos, int len) {
|
||||
super(w, doc, pos, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates HTML output
|
||||
* from a StyledDocument.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
* @exception BadLocationException if pos represents an invalid
|
||||
* location within the document.
|
||||
*
|
||||
*/
|
||||
public void write() throws IOException, BadLocationException {
|
||||
styleNameMapping = new Hashtable<String, String>();
|
||||
writeStartTag("<html>");
|
||||
writeHeader();
|
||||
writeBody();
|
||||
writeEndTag("</html>");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes out all the attributes for the
|
||||
* following types:
|
||||
* StyleConstants.ParagraphConstants,
|
||||
* StyleConstants.CharacterConstants,
|
||||
* StyleConstants.FontConstants,
|
||||
* StyleConstants.ColorConstants.
|
||||
* The attribute name and value are separated by a colon.
|
||||
* Each pair is separated by a semicolon.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
*/
|
||||
protected void writeAttributes(AttributeSet attr) throws IOException {
|
||||
Enumeration attributeNames = attr.getAttributeNames();
|
||||
while (attributeNames.hasMoreElements()) {
|
||||
Object name = attributeNames.nextElement();
|
||||
if ((name instanceof StyleConstants.ParagraphConstants) ||
|
||||
(name instanceof StyleConstants.CharacterConstants) ||
|
||||
(name instanceof StyleConstants.FontConstants) ||
|
||||
(name instanceof StyleConstants.ColorConstants)) {
|
||||
indent();
|
||||
write(name.toString());
|
||||
write(':');
|
||||
write(css.styleConstantsValueToCSSValue
|
||||
((StyleConstants)name, attr.getAttribute(name)).
|
||||
toString());
|
||||
write(';');
|
||||
write(NEWLINE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes out text.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
*/
|
||||
protected void text(Element elem) throws IOException, BadLocationException {
|
||||
String contentStr = getText(elem);
|
||||
if ((contentStr.length() > 0) &&
|
||||
(contentStr.charAt(contentStr.length()-1) == NEWLINE)) {
|
||||
contentStr = contentStr.substring(0, contentStr.length()-1);
|
||||
}
|
||||
if (contentStr.length() > 0) {
|
||||
write(contentStr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes out a start tag appropriately
|
||||
* indented. Also increments the indent level.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
*/
|
||||
protected void writeStartTag(String tag) throws IOException {
|
||||
indent();
|
||||
write(tag);
|
||||
write(NEWLINE);
|
||||
incrIndent();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes out an end tag appropriately
|
||||
* indented. Also decrements the indent level.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
*/
|
||||
protected void writeEndTag(String endTag) throws IOException {
|
||||
decrIndent();
|
||||
indent();
|
||||
write(endTag);
|
||||
write(NEWLINE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes out the <head> and <style>
|
||||
* tags, and then invokes writeStyles() to write
|
||||
* out all the named styles as the content of the
|
||||
* <style> tag. The content is surrounded by
|
||||
* valid HTML comment markers to ensure that the
|
||||
* document is viewable in applications/browsers
|
||||
* that do not support the tag.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
*/
|
||||
protected void writeHeader() throws IOException {
|
||||
writeStartTag("<head>");
|
||||
writeStartTag("<style>");
|
||||
writeStartTag("<!--");
|
||||
writeStyles();
|
||||
writeEndTag("-->");
|
||||
writeEndTag("</style>");
|
||||
writeEndTag("</head>");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Writes out all the named styles as the
|
||||
* content of the <style> tag.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
*/
|
||||
protected void writeStyles() throws IOException {
|
||||
/*
|
||||
* Access to DefaultStyledDocument done to workaround
|
||||
* a missing API in styled document to access the
|
||||
* stylenames.
|
||||
*/
|
||||
DefaultStyledDocument styledDoc = ((DefaultStyledDocument)getDocument());
|
||||
Enumeration styleNames = styledDoc.getStyleNames();
|
||||
|
||||
while (styleNames.hasMoreElements()) {
|
||||
Style s = styledDoc.getStyle((String)styleNames.nextElement());
|
||||
|
||||
/** PENDING: Once the name attribute is removed
|
||||
from the list we check check for 0. **/
|
||||
if (s.getAttributeCount() == 1 &&
|
||||
s.isDefined(StyleConstants.NameAttribute)) {
|
||||
continue;
|
||||
}
|
||||
indent();
|
||||
write("p." + addStyleName(s.getName()));
|
||||
write(" {\n");
|
||||
incrIndent();
|
||||
writeAttributes(s);
|
||||
decrIndent();
|
||||
indent();
|
||||
write("}\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Iterates over the elements in the document
|
||||
* and processes elements based on whether they are
|
||||
* branch elements or leaf elements. This method specially handles
|
||||
* leaf elements that are text.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
*/
|
||||
protected void writeBody() throws IOException, BadLocationException {
|
||||
ElementIterator it = getElementIterator();
|
||||
|
||||
/*
|
||||
This will be a section element for a styled document.
|
||||
We represent this element in HTML as the body tags.
|
||||
Therefore we ignore it.
|
||||
*/
|
||||
it.current();
|
||||
|
||||
Element next;
|
||||
|
||||
writeStartTag("<body>");
|
||||
|
||||
boolean inContent = false;
|
||||
|
||||
while((next = it.next()) != null) {
|
||||
if (!inRange(next)) {
|
||||
continue;
|
||||
}
|
||||
if (next instanceof AbstractDocument.BranchElement) {
|
||||
if (inContent) {
|
||||
writeEndParagraph();
|
||||
inContent = false;
|
||||
fontMask = 0;
|
||||
}
|
||||
writeStartParagraph(next);
|
||||
} else if (isText(next)) {
|
||||
writeContent(next, !inContent);
|
||||
inContent = true;
|
||||
} else {
|
||||
writeLeaf(next);
|
||||
inContent = true;
|
||||
}
|
||||
}
|
||||
if (inContent) {
|
||||
writeEndParagraph();
|
||||
}
|
||||
writeEndTag("</body>");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Emits an end tag for a <p>
|
||||
* tag. Before writing out the tag, this method ensures
|
||||
* that all other tags that have been opened are
|
||||
* appropriately closed off.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
*/
|
||||
protected void writeEndParagraph() throws IOException {
|
||||
writeEndMask(fontMask);
|
||||
if (inFontTag()) {
|
||||
endSpanTag();
|
||||
} else {
|
||||
write(NEWLINE);
|
||||
}
|
||||
writeEndTag("</p>");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Emits the start tag for a paragraph. If
|
||||
* the paragraph has a named style associated with it,
|
||||
* then this method also generates a class attribute for the
|
||||
* <p> tag and sets its value to be the name of the
|
||||
* style.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
*/
|
||||
protected void writeStartParagraph(Element elem) throws IOException {
|
||||
AttributeSet attr = elem.getAttributes();
|
||||
Object resolveAttr = attr.getAttribute(StyleConstants.ResolveAttribute);
|
||||
if (resolveAttr instanceof StyleContext.NamedStyle) {
|
||||
writeStartTag("<p class=" + mapStyleName(((StyleContext.NamedStyle)resolveAttr).getName()) + ">");
|
||||
} else {
|
||||
writeStartTag("<p>");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Responsible for writing out other non-text leaf
|
||||
* elements.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
*/
|
||||
protected void writeLeaf(Element elem) throws IOException {
|
||||
indent();
|
||||
if (elem.getName() == StyleConstants.IconElementName) {
|
||||
writeImage(elem);
|
||||
} else if (elem.getName() == StyleConstants.ComponentElementName) {
|
||||
writeComponent(elem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Responsible for handling Icon Elements;
|
||||
* deliberately unimplemented. How to implement this method is
|
||||
* an issue of policy. For example, if you're generating
|
||||
* an <img> tag, how should you
|
||||
* represent the src attribute (the location of the image)?
|
||||
* In certain cases it could be a URL, in others it could
|
||||
* be read from a stream.
|
||||
*
|
||||
* @param elem element of type StyleConstants.IconElementName
|
||||
*/
|
||||
protected void writeImage(Element elem) throws IOException {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Responsible for handling Component Elements;
|
||||
* deliberately unimplemented.
|
||||
* How this method is implemented is a matter of policy.
|
||||
*/
|
||||
protected void writeComponent(Element elem) throws IOException {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the element is a text element.
|
||||
*
|
||||
*/
|
||||
protected boolean isText(Element elem) {
|
||||
return (elem.getName() == AbstractDocument.ContentElementName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes out the attribute set
|
||||
* in an HTML-compliant manner.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
* @exception BadLocationException if pos represents an invalid
|
||||
* location within the document.
|
||||
*/
|
||||
protected void writeContent(Element elem, boolean needsIndenting)
|
||||
throws IOException, BadLocationException {
|
||||
|
||||
AttributeSet attr = elem.getAttributes();
|
||||
writeNonHTMLAttributes(attr);
|
||||
if (needsIndenting) {
|
||||
indent();
|
||||
}
|
||||
writeHTMLTags(attr);
|
||||
text(elem);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates
|
||||
* bold <b>, italic <i>, and <u> tags for the
|
||||
* text based on its attribute settings.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
*/
|
||||
|
||||
protected void writeHTMLTags(AttributeSet attr) throws IOException {
|
||||
|
||||
int oldMask = fontMask;
|
||||
setFontMask(attr);
|
||||
|
||||
int endMask = 0;
|
||||
int startMask = 0;
|
||||
if ((oldMask & BOLD) != 0) {
|
||||
if ((fontMask & BOLD) == 0) {
|
||||
endMask |= BOLD;
|
||||
}
|
||||
} else if ((fontMask & BOLD) != 0) {
|
||||
startMask |= BOLD;
|
||||
}
|
||||
|
||||
if ((oldMask & ITALIC) != 0) {
|
||||
if ((fontMask & ITALIC) == 0) {
|
||||
endMask |= ITALIC;
|
||||
}
|
||||
} else if ((fontMask & ITALIC) != 0) {
|
||||
startMask |= ITALIC;
|
||||
}
|
||||
|
||||
if ((oldMask & UNDERLINE) != 0) {
|
||||
if ((fontMask & UNDERLINE) == 0) {
|
||||
endMask |= UNDERLINE;
|
||||
}
|
||||
} else if ((fontMask & UNDERLINE) != 0) {
|
||||
startMask |= UNDERLINE;
|
||||
}
|
||||
writeEndMask(endMask);
|
||||
writeStartMask(startMask);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tweaks the appropriate bits of fontMask
|
||||
* to reflect whether the text is to be displayed in
|
||||
* bold, italic, and/or with an underline.
|
||||
*
|
||||
*/
|
||||
private void setFontMask(AttributeSet attr) {
|
||||
if (StyleConstants.isBold(attr)) {
|
||||
fontMask |= BOLD;
|
||||
}
|
||||
|
||||
if (StyleConstants.isItalic(attr)) {
|
||||
fontMask |= ITALIC;
|
||||
}
|
||||
|
||||
if (StyleConstants.isUnderline(attr)) {
|
||||
fontMask |= UNDERLINE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Writes out start tags <u>, <i>, and <b> based on
|
||||
* the mask settings.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
*/
|
||||
private void writeStartMask(int mask) throws IOException {
|
||||
if (mask != 0) {
|
||||
if ((mask & UNDERLINE) != 0) {
|
||||
write("<u>");
|
||||
}
|
||||
if ((mask & ITALIC) != 0) {
|
||||
write("<i>");
|
||||
}
|
||||
if ((mask & BOLD) != 0) {
|
||||
write("<b>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes out end tags for <u>, <i>, and <b> based on
|
||||
* the mask settings.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
*/
|
||||
private void writeEndMask(int mask) throws IOException {
|
||||
if (mask != 0) {
|
||||
if ((mask & BOLD) != 0) {
|
||||
write("</b>");
|
||||
}
|
||||
if ((mask & ITALIC) != 0) {
|
||||
write("</i>");
|
||||
}
|
||||
if ((mask & UNDERLINE) != 0) {
|
||||
write("</u>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes out the remaining
|
||||
* character-level attributes (attributes other than bold,
|
||||
* italic, and underline) in an HTML-compliant way. Given that
|
||||
* attributes such as font family and font size have no direct
|
||||
* mapping to HTML tags, a <span> tag is generated and its
|
||||
* style attribute is set to contain the list of remaining
|
||||
* attributes just like inline styles.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
*/
|
||||
protected void writeNonHTMLAttributes(AttributeSet attr) throws IOException {
|
||||
|
||||
String style = "";
|
||||
String separator = "; ";
|
||||
|
||||
if (inFontTag() && fontAttributes.isEqual(attr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean first = true;
|
||||
Color color = (Color)attr.getAttribute(StyleConstants.Foreground);
|
||||
if (color != null) {
|
||||
style += "color: " + css.styleConstantsValueToCSSValue
|
||||
((StyleConstants)StyleConstants.Foreground,
|
||||
color);
|
||||
first = false;
|
||||
}
|
||||
Integer size = (Integer)attr.getAttribute(StyleConstants.FontSize);
|
||||
if (size != null) {
|
||||
if (!first) {
|
||||
style += separator;
|
||||
}
|
||||
style += "font-size: " + size.intValue() + "pt";
|
||||
first = false;
|
||||
}
|
||||
|
||||
String family = (String)attr.getAttribute(StyleConstants.FontFamily);
|
||||
if (family != null) {
|
||||
if (!first) {
|
||||
style += separator;
|
||||
}
|
||||
style += "font-family: " + family;
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (style.length() > 0) {
|
||||
if (fontMask != 0) {
|
||||
writeEndMask(fontMask);
|
||||
fontMask = 0;
|
||||
}
|
||||
startSpanTag(style);
|
||||
fontAttributes = attr;
|
||||
}
|
||||
else if (fontAttributes != null) {
|
||||
writeEndMask(fontMask);
|
||||
fontMask = 0;
|
||||
endSpanTag();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if we are currently in a <font> tag.
|
||||
*/
|
||||
protected boolean inFontTag() {
|
||||
return (fontAttributes != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is no longer used, instead <span> will be written out.
|
||||
* <p>
|
||||
* Writes out an end tag for the <font> tag.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
*/
|
||||
protected void endFontTag() throws IOException {
|
||||
write(NEWLINE);
|
||||
writeEndTag("</font>");
|
||||
fontAttributes = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is no longer used, instead <span> will be written out.
|
||||
* <p>
|
||||
* Writes out a start tag for the <font> tag.
|
||||
* Because font tags cannot be nested,
|
||||
* this method closes out
|
||||
* any enclosing font tag before writing out a
|
||||
* new start tag.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
*/
|
||||
protected void startFontTag(String style) throws IOException {
|
||||
boolean callIndent = false;
|
||||
if (inFontTag()) {
|
||||
endFontTag();
|
||||
callIndent = true;
|
||||
}
|
||||
writeStartTag("<font style=\"" + style + "\">");
|
||||
if (callIndent) {
|
||||
indent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes out a start tag for the <font> tag.
|
||||
* Because font tags cannot be nested,
|
||||
* this method closes out
|
||||
* any enclosing font tag before writing out a
|
||||
* new start tag.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
*/
|
||||
private void startSpanTag(String style) throws IOException {
|
||||
boolean callIndent = false;
|
||||
if (inFontTag()) {
|
||||
endSpanTag();
|
||||
callIndent = true;
|
||||
}
|
||||
writeStartTag("<span style=\"" + style + "\">");
|
||||
if (callIndent) {
|
||||
indent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes out an end tag for the <span> tag.
|
||||
*
|
||||
* @exception IOException on any I/O error
|
||||
*/
|
||||
private void endSpanTag() throws IOException {
|
||||
write(NEWLINE);
|
||||
writeEndTag("</span>");
|
||||
fontAttributes = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the style named <code>style</code> to the style mapping. This
|
||||
* returns the name that should be used when outputting. CSS does not
|
||||
* allow the full Unicode set to be used as a style name.
|
||||
*/
|
||||
private String addStyleName(String style) {
|
||||
if (styleNameMapping == null) {
|
||||
return style;
|
||||
}
|
||||
StringBuilder sb = null;
|
||||
for (int counter = style.length() - 1; counter >= 0; counter--) {
|
||||
if (!isValidCharacter(style.charAt(counter))) {
|
||||
if (sb == null) {
|
||||
sb = new StringBuilder(style);
|
||||
}
|
||||
sb.setCharAt(counter, 'a');
|
||||
}
|
||||
}
|
||||
String mappedName = (sb != null) ? sb.toString() : style;
|
||||
while (styleNameMapping.get(mappedName) != null) {
|
||||
mappedName = mappedName + 'x';
|
||||
}
|
||||
styleNameMapping.put(style, mappedName);
|
||||
return mappedName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mapped style name corresponding to <code>style</code>.
|
||||
*/
|
||||
private String mapStyleName(String style) {
|
||||
if (styleNameMapping == null) {
|
||||
return style;
|
||||
}
|
||||
String retValue = styleNameMapping.get(style);
|
||||
return (retValue == null) ? style : retValue;
|
||||
}
|
||||
|
||||
private boolean isValidCharacter(char character) {
|
||||
return ((character >= 'a' && character <= 'z') ||
|
||||
(character >= 'A' && character <= 'Z'));
|
||||
}
|
||||
}
|
||||
311
jdkSrc/jdk8/javax/swing/text/html/MuxingAttributeSet.java
Normal file
311
jdkSrc/jdk8/javax/swing/text/html/MuxingAttributeSet.java
Normal file
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import javax.swing.text.*;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* An implementation of <code>AttributeSet</code> that can multiplex
|
||||
* across a set of <code>AttributeSet</code>s.
|
||||
*
|
||||
*/
|
||||
class MuxingAttributeSet implements AttributeSet, Serializable {
|
||||
/**
|
||||
* Creates a <code>MuxingAttributeSet</code> with the passed in
|
||||
* attributes.
|
||||
*/
|
||||
public MuxingAttributeSet(AttributeSet[] attrs) {
|
||||
this.attrs = attrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty <code>MuxingAttributeSet</code>. This is intended for
|
||||
* use by subclasses only, and it is also intended that subclasses will
|
||||
* set the constituent <code>AttributeSet</code>s before invoking any
|
||||
* of the <code>AttributeSet</code> methods.
|
||||
*/
|
||||
protected MuxingAttributeSet() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly sets the <code>AttributeSet</code>s that comprise this
|
||||
* <code>MuxingAttributeSet</code>.
|
||||
*/
|
||||
protected synchronized void setAttributes(AttributeSet[] attrs) {
|
||||
this.attrs = attrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>AttributeSet</code>s multiplexing too. When the
|
||||
* <code>AttributeSet</code>s need to be referenced, this should be called.
|
||||
*/
|
||||
protected synchronized AttributeSet[] getAttributes() {
|
||||
return attrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts <code>as</code> at <code>index</code>. This assumes
|
||||
* the value of <code>index</code> is between 0 and attrs.length,
|
||||
* inclusive.
|
||||
*/
|
||||
protected synchronized void insertAttributeSetAt(AttributeSet as,
|
||||
int index) {
|
||||
int numAttrs = attrs.length;
|
||||
AttributeSet newAttrs[] = new AttributeSet[numAttrs + 1];
|
||||
if (index < numAttrs) {
|
||||
if (index > 0) {
|
||||
System.arraycopy(attrs, 0, newAttrs, 0, index);
|
||||
System.arraycopy(attrs, index, newAttrs, index + 1,
|
||||
numAttrs - index);
|
||||
}
|
||||
else {
|
||||
System.arraycopy(attrs, 0, newAttrs, 1, numAttrs);
|
||||
}
|
||||
}
|
||||
else {
|
||||
System.arraycopy(attrs, 0, newAttrs, 0, numAttrs);
|
||||
}
|
||||
newAttrs[index] = as;
|
||||
attrs = newAttrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the AttributeSet at <code>index</code>. This assumes
|
||||
* the value of <code>index</code> is greater than or equal to 0,
|
||||
* and less than attrs.length.
|
||||
*/
|
||||
protected synchronized void removeAttributeSetAt(int index) {
|
||||
int numAttrs = attrs.length;
|
||||
AttributeSet[] newAttrs = new AttributeSet[numAttrs - 1];
|
||||
if (numAttrs > 0) {
|
||||
if (index == 0) {
|
||||
// FIRST
|
||||
System.arraycopy(attrs, 1, newAttrs, 0, numAttrs - 1);
|
||||
}
|
||||
else if (index < (numAttrs - 1)) {
|
||||
// MIDDLE
|
||||
System.arraycopy(attrs, 0, newAttrs, 0, index);
|
||||
System.arraycopy(attrs, index + 1, newAttrs, index,
|
||||
numAttrs - index - 1);
|
||||
}
|
||||
else {
|
||||
// END
|
||||
System.arraycopy(attrs, 0, newAttrs, 0, numAttrs - 1);
|
||||
}
|
||||
}
|
||||
attrs = newAttrs;
|
||||
}
|
||||
|
||||
// --- AttributeSet methods ----------------------------
|
||||
|
||||
/**
|
||||
* Gets the number of attributes that are defined.
|
||||
*
|
||||
* @return the number of attributes
|
||||
* @see AttributeSet#getAttributeCount
|
||||
*/
|
||||
public int getAttributeCount() {
|
||||
AttributeSet[] as = getAttributes();
|
||||
int n = 0;
|
||||
for (int i = 0; i < as.length; i++) {
|
||||
n += as[i].getAttributeCount();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given attribute is defined.
|
||||
* This will convert the key over to CSS if the
|
||||
* key is a StyleConstants key that has a CSS
|
||||
* mapping.
|
||||
*
|
||||
* @param key the attribute key
|
||||
* @return true if the attribute is defined
|
||||
* @see AttributeSet#isDefined
|
||||
*/
|
||||
public boolean isDefined(Object key) {
|
||||
AttributeSet[] as = getAttributes();
|
||||
for (int i = 0; i < as.length; i++) {
|
||||
if (as[i].isDefined(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether two attribute sets are equal.
|
||||
*
|
||||
* @param attr the attribute set to check against
|
||||
* @return true if the same
|
||||
* @see AttributeSet#isEqual
|
||||
*/
|
||||
public boolean isEqual(AttributeSet attr) {
|
||||
return ((getAttributeCount() == attr.getAttributeCount()) &&
|
||||
containsAttributes(attr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies a set of attributes.
|
||||
*
|
||||
* @return the copy
|
||||
* @see AttributeSet#copyAttributes
|
||||
*/
|
||||
public AttributeSet copyAttributes() {
|
||||
AttributeSet[] as = getAttributes();
|
||||
MutableAttributeSet a = new SimpleAttributeSet();
|
||||
int n = 0;
|
||||
for (int i = as.length - 1; i >= 0; i--) {
|
||||
a.addAttributes(as[i]);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of an attribute. If the requested
|
||||
* attribute is a StyleConstants attribute that has
|
||||
* a CSS mapping, the request will be converted.
|
||||
*
|
||||
* @param key the attribute name
|
||||
* @return the attribute value
|
||||
* @see AttributeSet#getAttribute
|
||||
*/
|
||||
public Object getAttribute(Object key) {
|
||||
AttributeSet[] as = getAttributes();
|
||||
int n = as.length;
|
||||
for (int i = 0; i < n; i++) {
|
||||
Object o = as[i].getAttribute(key);
|
||||
if (o != null) {
|
||||
return o;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the names of all attributes.
|
||||
*
|
||||
* @return the attribute names
|
||||
* @see AttributeSet#getAttributeNames
|
||||
*/
|
||||
public Enumeration getAttributeNames() {
|
||||
return new MuxingAttributeNameEnumeration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given attribute name/value is defined.
|
||||
*
|
||||
* @param name the attribute name
|
||||
* @param value the attribute value
|
||||
* @return true if the name/value is defined
|
||||
* @see AttributeSet#containsAttribute
|
||||
*/
|
||||
public boolean containsAttribute(Object name, Object value) {
|
||||
return value.equals(getAttribute(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the attribute set contains all of
|
||||
* the given attributes.
|
||||
*
|
||||
* @param attrs the attributes to check
|
||||
* @return true if the element contains all the attributes
|
||||
* @see AttributeSet#containsAttributes
|
||||
*/
|
||||
public boolean containsAttributes(AttributeSet attrs) {
|
||||
boolean result = true;
|
||||
|
||||
Enumeration names = attrs.getAttributeNames();
|
||||
while (result && names.hasMoreElements()) {
|
||||
Object name = names.nextElement();
|
||||
result = attrs.getAttribute(name).equals(getAttribute(name));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null, subclasses may wish to do something more
|
||||
* intelligent with this.
|
||||
*/
|
||||
public AttributeSet getResolveParent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The <code>AttributeSet</code>s that make up the resulting
|
||||
* <code>AttributeSet</code>.
|
||||
*/
|
||||
private AttributeSet[] attrs;
|
||||
|
||||
|
||||
/**
|
||||
* An Enumeration of the Attribute names in a MuxingAttributeSet.
|
||||
* This may return the same name more than once.
|
||||
*/
|
||||
private class MuxingAttributeNameEnumeration implements Enumeration {
|
||||
|
||||
MuxingAttributeNameEnumeration() {
|
||||
updateEnum();
|
||||
}
|
||||
|
||||
public boolean hasMoreElements() {
|
||||
if (currentEnum == null) {
|
||||
return false;
|
||||
}
|
||||
return currentEnum.hasMoreElements();
|
||||
}
|
||||
|
||||
public Object nextElement() {
|
||||
if (currentEnum == null) {
|
||||
throw new NoSuchElementException("No more names");
|
||||
}
|
||||
Object retObject = currentEnum.nextElement();
|
||||
if (!currentEnum.hasMoreElements()) {
|
||||
updateEnum();
|
||||
}
|
||||
return retObject;
|
||||
}
|
||||
|
||||
void updateEnum() {
|
||||
AttributeSet[] as = getAttributes();
|
||||
currentEnum = null;
|
||||
while (currentEnum == null && attrIndex < as.length) {
|
||||
currentEnum = as[attrIndex++].getAttributeNames();
|
||||
if (!currentEnum.hasMoreElements()) {
|
||||
currentEnum = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Index into attrs the current Enumeration came from. */
|
||||
private int attrIndex;
|
||||
/** Enumeration from attrs. */
|
||||
private Enumeration currentEnum;
|
||||
}
|
||||
}
|
||||
173
jdkSrc/jdk8/javax/swing/text/html/NoFramesView.java
Normal file
173
jdkSrc/jdk8/javax/swing/text/html/NoFramesView.java
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import javax.swing.text.*;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* This is the view associated with the html tag NOFRAMES.
|
||||
* This view has been written to ignore the contents of the
|
||||
* NOFRAMES tag. The contents of the tag will only be visible
|
||||
* when the JTextComponent the view is contained in is editable.
|
||||
*
|
||||
* @author Sunita Mani
|
||||
*/
|
||||
class NoFramesView extends BlockView {
|
||||
|
||||
/**
|
||||
* Creates a new view that represents an
|
||||
* html box. This can be used for a number
|
||||
* of elements. By default this view is not
|
||||
* visible.
|
||||
*
|
||||
* @param elem the element to create a view for
|
||||
* @param axis either View.X_AXIS or View.Y_AXIS
|
||||
*/
|
||||
public NoFramesView(Element elem, int axis) {
|
||||
super(elem, axis);
|
||||
visible = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If this view is not visible, then it returns.
|
||||
* Otherwise it invokes the superclass.
|
||||
*
|
||||
* @param g the rendering surface to use
|
||||
* @param allocation the allocated region to render into
|
||||
* @see #isVisible
|
||||
* @see text.ParagraphView#paint
|
||||
*/
|
||||
public void paint(Graphics g, Shape allocation) {
|
||||
Container host = getContainer();
|
||||
if (host != null &&
|
||||
visible != ((JTextComponent)host).isEditable()) {
|
||||
visible = ((JTextComponent)host).isEditable();
|
||||
}
|
||||
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
super.paint(g, allocation);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines if the JTextComponent that the view
|
||||
* is contained in is editable. If so, then this
|
||||
* view and all its child views are visible.
|
||||
* Once this has been determined, the superclass
|
||||
* is invoked to continue processing.
|
||||
*
|
||||
* @param p the parent View.
|
||||
* @see BlockView#setParent
|
||||
*/
|
||||
public void setParent(View p) {
|
||||
if (p != null) {
|
||||
Container host = p.getContainer();
|
||||
if (host != null) {
|
||||
visible = ((JTextComponent)host).isEditable();
|
||||
}
|
||||
}
|
||||
super.setParent(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a true/false value that represents
|
||||
* whether the view is visible or not.
|
||||
*/
|
||||
public boolean isVisible() {
|
||||
return visible;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Do nothing if the view is not visible, otherwise
|
||||
* invoke the superclass to perform layout.
|
||||
*/
|
||||
protected void layout(int width, int height) {
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
super.layout(width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the preferred span for this view. Returns
|
||||
* 0 if the view is not visible, otherwise it calls the
|
||||
* superclass method to get the preferred span.
|
||||
* axis.
|
||||
*
|
||||
* @param axis may be either View.X_AXIS or View.Y_AXIS
|
||||
* @return the span the view would like to be rendered into;
|
||||
* typically the view is told to render into the span
|
||||
* that is returned, although there is no guarantee;
|
||||
* the parent may choose to resize or break the view
|
||||
* @see text.ParagraphView#getPreferredSpan
|
||||
*/
|
||||
public float getPreferredSpan(int axis) {
|
||||
if (!visible) {
|
||||
return 0;
|
||||
}
|
||||
return super.getPreferredSpan(axis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the minimum span for this view along an
|
||||
* axis. Returns 0 if the view is not visible, otherwise
|
||||
* it calls the superclass method to get the minimum span.
|
||||
*
|
||||
* @param axis may be either <code>View.X_AXIS</code> or
|
||||
* <code>View.Y_AXIS</code>
|
||||
* @return the minimum span the view can be rendered into
|
||||
* @see text.ParagraphView#getMinimumSpan
|
||||
*/
|
||||
public float getMinimumSpan(int axis) {
|
||||
if (!visible) {
|
||||
return 0;
|
||||
}
|
||||
return super.getMinimumSpan(axis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the maximum span for this view along an
|
||||
* axis. Returns 0 if the view is not visible, otherwise
|
||||
* it calls the superclass method ot get the maximum span.
|
||||
*
|
||||
* @param axis may be either <code>View.X_AXIS</code> or
|
||||
* <code>View.Y_AXIS</code>
|
||||
* @return the maximum span the view can be rendered into
|
||||
* @see text.ParagraphView#getMaximumSpan
|
||||
*/
|
||||
public float getMaximumSpan(int axis) {
|
||||
if (!visible) {
|
||||
return 0;
|
||||
}
|
||||
return super.getMaximumSpan(axis);
|
||||
}
|
||||
|
||||
boolean visible;
|
||||
}
|
||||
176
jdkSrc/jdk8/javax/swing/text/html/ObjectView.java
Normal file
176
jdkSrc/jdk8/javax/swing/text/html/ObjectView.java
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.awt.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.*;
|
||||
import java.beans.*;
|
||||
import java.lang.reflect.*;
|
||||
|
||||
import sun.reflect.misc.MethodUtil;
|
||||
import sun.reflect.misc.ReflectUtil;
|
||||
|
||||
/**
|
||||
* Component decorator that implements the view interface
|
||||
* for <object> elements.
|
||||
* <p>
|
||||
* This view will try to load the class specified by the
|
||||
* <code>classid</code> attribute. If possible, the Classloader
|
||||
* used to load the associated Document is used.
|
||||
* This would typically be the same as the ClassLoader
|
||||
* used to load the EditorKit. If the document's
|
||||
* ClassLoader is null, <code>Class.forName</code> is used.
|
||||
* <p>
|
||||
* If the class can successfully be loaded, an attempt will
|
||||
* be made to create an instance of it by calling
|
||||
* <code>Class.newInstance</code>. An attempt will be made
|
||||
* to narrow the instance to type <code>java.awt.Component</code>
|
||||
* to display the object.
|
||||
* <p>
|
||||
* This view can also manage a set of parameters with limitations.
|
||||
* The parameters to the <object> element are expected to
|
||||
* be present on the associated elements attribute set as simple
|
||||
* strings. Each bean property will be queried as a key on
|
||||
* the AttributeSet, with the expectation that a non-null value
|
||||
* (of type String) will be present if there was a parameter
|
||||
* specification for the property. Reflection is used to
|
||||
* set the parameter. Currently, this is limited to a very
|
||||
* simple single parameter of type String.
|
||||
* <p>
|
||||
* A simple example HTML invocation is:
|
||||
* <pre>
|
||||
* <object classid="javax.swing.JLabel">
|
||||
* <param name="text" value="sample text">
|
||||
* </object>
|
||||
* </pre>
|
||||
*
|
||||
* @author Timothy Prinzing
|
||||
*/
|
||||
public class ObjectView extends ComponentView {
|
||||
|
||||
private boolean createComp = true; // default
|
||||
|
||||
/**
|
||||
* Creates a new ObjectView object.
|
||||
*
|
||||
* @param elem the element to decorate
|
||||
*/
|
||||
public ObjectView(Element elem) {
|
||||
super(elem);
|
||||
}
|
||||
|
||||
ObjectView(Element elem, boolean createComp) {
|
||||
super(elem);
|
||||
this.createComp = createComp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the component. The classid is used
|
||||
* as a specification of the classname, which
|
||||
* we try to load.
|
||||
*/
|
||||
protected Component createComponent() {
|
||||
if (!createComp) {
|
||||
return getUnloadableRepresentation();
|
||||
}
|
||||
AttributeSet attr = getElement().getAttributes();
|
||||
String classname = (String) attr.getAttribute(HTML.Attribute.CLASSID);
|
||||
try {
|
||||
ReflectUtil.checkPackageAccess(classname);
|
||||
Class c = Class.forName(classname, false,Thread.currentThread().
|
||||
getContextClassLoader());
|
||||
if (Component.class.isAssignableFrom(c)) {
|
||||
Object o = c.newInstance();
|
||||
if (o instanceof Component) {
|
||||
Component comp = (Component) o;
|
||||
setParameters(comp, attr);
|
||||
return comp;
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// couldn't create a component... fall through to the
|
||||
// couldn't load representation.
|
||||
}
|
||||
|
||||
return getUnloadableRepresentation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a component that can be used to represent the
|
||||
* object if it can't be created.
|
||||
*/
|
||||
Component getUnloadableRepresentation() {
|
||||
// PENDING(prinz) get some artwork and return something
|
||||
// interesting here.
|
||||
Component comp = new JLabel("??");
|
||||
comp.setForeground(Color.red);
|
||||
return comp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this component according the KEY/VALUEs passed in
|
||||
* via the <param> elements in the corresponding
|
||||
* <object> element.
|
||||
*/
|
||||
private void setParameters(Component comp, AttributeSet attr) {
|
||||
Class k = comp.getClass();
|
||||
BeanInfo bi;
|
||||
try {
|
||||
bi = Introspector.getBeanInfo(k);
|
||||
} catch (IntrospectionException ex) {
|
||||
System.err.println("introspector failed, ex: "+ex);
|
||||
return; // quit for now
|
||||
}
|
||||
PropertyDescriptor props[] = bi.getPropertyDescriptors();
|
||||
for (int i=0; i < props.length; i++) {
|
||||
// System.err.println("checking on props[i]: "+props[i].getName());
|
||||
Object v = attr.getAttribute(props[i].getName());
|
||||
if (v instanceof String) {
|
||||
// found a property parameter
|
||||
String value = (String) v;
|
||||
Method writer = props[i].getWriteMethod();
|
||||
if (writer == null) {
|
||||
// read-only property. ignore
|
||||
return; // for now
|
||||
}
|
||||
Class[] params = writer.getParameterTypes();
|
||||
if (params.length != 1) {
|
||||
// zero or more than one argument, ignore
|
||||
return; // for now
|
||||
}
|
||||
Object [] args = { value };
|
||||
try {
|
||||
MethodUtil.invoke(writer, comp, args);
|
||||
} catch (Exception ex) {
|
||||
System.err.println("Invocation failed");
|
||||
// invocation code
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
120
jdkSrc/jdk8/javax/swing/text/html/Option.java
Normal file
120
jdkSrc/jdk8/javax/swing/text/html/Option.java
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.io.Serializable;
|
||||
import javax.swing.text.*;
|
||||
|
||||
/**
|
||||
* Value for the ListModel used to represent
|
||||
* <option> elements. This is the object
|
||||
* installed as items of the DefaultComboBoxModel
|
||||
* used to represent the <select> element.
|
||||
* <p>
|
||||
* <strong>Warning:</strong>
|
||||
* Serialized objects of this class will not be compatible with
|
||||
* future Swing releases. The current serialization support is
|
||||
* appropriate for short term storage or RMI between applications running
|
||||
* the same version of Swing. As of 1.4, support for long term storage
|
||||
* of all JavaBeans™
|
||||
* has been added to the <code>java.beans</code> package.
|
||||
* Please see {@link java.beans.XMLEncoder}.
|
||||
*
|
||||
* @author Timothy Prinzing
|
||||
*/
|
||||
public class Option implements Serializable {
|
||||
|
||||
/**
|
||||
* Creates a new Option object.
|
||||
*
|
||||
* @param attr the attributes associated with the
|
||||
* option element. The attributes are copied to
|
||||
* ensure they won't change.
|
||||
*/
|
||||
public Option(AttributeSet attr) {
|
||||
this.attr = attr.copyAttributes();
|
||||
selected = (attr.getAttribute(HTML.Attribute.SELECTED) != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the label to be used for the option.
|
||||
*/
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the label associated with the option.
|
||||
*/
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the attributes associated with this option.
|
||||
*/
|
||||
public AttributeSet getAttributes() {
|
||||
return attr;
|
||||
}
|
||||
|
||||
/**
|
||||
* String representation is the label.
|
||||
*/
|
||||
public String toString() {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the selected state.
|
||||
*/
|
||||
protected void setSelection(boolean state) {
|
||||
selected = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the selection state associated with this option.
|
||||
*/
|
||||
public boolean isSelected() {
|
||||
return selected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to return the string associated
|
||||
* with the <code>value</code> attribute. If the
|
||||
* value has not been specified, the label will be
|
||||
* returned.
|
||||
*/
|
||||
public String getValue() {
|
||||
String value = (String) attr.getAttribute(HTML.Attribute.VALUE);
|
||||
if (value == null) {
|
||||
value = label;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private boolean selected;
|
||||
private String label;
|
||||
private AttributeSet attr;
|
||||
}
|
||||
62
jdkSrc/jdk8/javax/swing/text/html/OptionComboBoxModel.java
Normal file
62
jdkSrc/jdk8/javax/swing/text/html/OptionComboBoxModel.java
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* OptionComboBoxModel extends the capabilities of the DefaultComboBoxModel,
|
||||
* to store the Option that is initially marked as selected.
|
||||
* This is stored, in order to enable an accurate reset of the
|
||||
* ComboBox that represents the SELECT form element when the
|
||||
* user requests a clear/reset. Given that a combobox only allow
|
||||
* for one item to be selected, the last OPTION that has the
|
||||
* attribute set wins.
|
||||
*
|
||||
@author Sunita Mani
|
||||
*/
|
||||
|
||||
class OptionComboBoxModel<E> extends DefaultComboBoxModel<E> implements Serializable {
|
||||
|
||||
private Option selectedOption = null;
|
||||
|
||||
/**
|
||||
* Stores the Option that has been marked its
|
||||
* selected attribute set.
|
||||
*/
|
||||
public void setInitialSelection(Option option) {
|
||||
selectedOption = option;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the Option item that represents that was
|
||||
* initially set to a selected state.
|
||||
*/
|
||||
public Option getInitialSelection() {
|
||||
return selectedOption;
|
||||
}
|
||||
}
|
||||
569
jdkSrc/jdk8/javax/swing/text/html/OptionListModel.java
Normal file
569
jdkSrc/jdk8/javax/swing/text/html/OptionListModel.java
Normal file
@@ -0,0 +1,569 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import java.util.BitSet;
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* This class extends DefaultListModel, and also implements
|
||||
* the ListSelectionModel interface, allowing for it to store state
|
||||
* relevant to a SELECT form element which is implemented as a List.
|
||||
* If SELECT has a size attribute whose value is greater than 1,
|
||||
* or if allows multiple selection then a JList is used to
|
||||
* represent it and the OptionListModel is used as its model.
|
||||
* It also stores the initial state of the JList, to ensure an
|
||||
* accurate reset, if the user requests a reset of the form.
|
||||
*
|
||||
@author Sunita Mani
|
||||
*/
|
||||
|
||||
class OptionListModel<E> extends DefaultListModel<E> implements ListSelectionModel, Serializable {
|
||||
|
||||
|
||||
private static final int MIN = -1;
|
||||
private static final int MAX = Integer.MAX_VALUE;
|
||||
private int selectionMode = SINGLE_SELECTION;
|
||||
private int minIndex = MAX;
|
||||
private int maxIndex = MIN;
|
||||
private int anchorIndex = -1;
|
||||
private int leadIndex = -1;
|
||||
private int firstChangedIndex = MAX;
|
||||
private int lastChangedIndex = MIN;
|
||||
private boolean isAdjusting = false;
|
||||
private BitSet value = new BitSet(32);
|
||||
private BitSet initialValue = new BitSet(32);
|
||||
protected EventListenerList listenerList = new EventListenerList();
|
||||
|
||||
protected boolean leadAnchorNotificationEnabled = true;
|
||||
|
||||
public int getMinSelectionIndex() { return isSelectionEmpty() ? -1 : minIndex; }
|
||||
|
||||
public int getMaxSelectionIndex() { return maxIndex; }
|
||||
|
||||
public boolean getValueIsAdjusting() { return isAdjusting; }
|
||||
|
||||
public int getSelectionMode() { return selectionMode; }
|
||||
|
||||
public void setSelectionMode(int selectionMode) {
|
||||
switch (selectionMode) {
|
||||
case SINGLE_SELECTION:
|
||||
case SINGLE_INTERVAL_SELECTION:
|
||||
case MULTIPLE_INTERVAL_SELECTION:
|
||||
this.selectionMode = selectionMode;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("invalid selectionMode");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSelectedIndex(int index) {
|
||||
return ((index < minIndex) || (index > maxIndex)) ? false : value.get(index);
|
||||
}
|
||||
|
||||
public boolean isSelectionEmpty() {
|
||||
return (minIndex > maxIndex);
|
||||
}
|
||||
|
||||
public void addListSelectionListener(ListSelectionListener l) {
|
||||
listenerList.add(ListSelectionListener.class, l);
|
||||
}
|
||||
|
||||
public void removeListSelectionListener(ListSelectionListener l) {
|
||||
listenerList.remove(ListSelectionListener.class, l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all the <code>ListSelectionListener</code>s added
|
||||
* to this OptionListModel with addListSelectionListener().
|
||||
*
|
||||
* @return all of the <code>ListSelectionListener</code>s added or an empty
|
||||
* array if no listeners have been added
|
||||
* @since 1.4
|
||||
*/
|
||||
public ListSelectionListener[] getListSelectionListeners() {
|
||||
return listenerList.getListeners(ListSelectionListener.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify listeners that we are beginning or ending a
|
||||
* series of value changes
|
||||
*/
|
||||
protected void fireValueChanged(boolean isAdjusting) {
|
||||
fireValueChanged(getMinSelectionIndex(), getMaxSelectionIndex(), isAdjusting);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notify ListSelectionListeners that the value of the selection,
|
||||
* in the closed interval firstIndex,lastIndex, has changed.
|
||||
*/
|
||||
protected void fireValueChanged(int firstIndex, int lastIndex) {
|
||||
fireValueChanged(firstIndex, lastIndex, getValueIsAdjusting());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param firstIndex The first index in the interval.
|
||||
* @param lastIndex The last index in the interval.
|
||||
* @param isAdjusting True if this is the final change in a series of them.
|
||||
* @see EventListenerList
|
||||
*/
|
||||
protected void fireValueChanged(int firstIndex, int lastIndex, boolean isAdjusting)
|
||||
{
|
||||
Object[] listeners = listenerList.getListenerList();
|
||||
ListSelectionEvent e = null;
|
||||
|
||||
for (int i = listeners.length - 2; i >= 0; i -= 2) {
|
||||
if (listeners[i] == ListSelectionListener.class) {
|
||||
if (e == null) {
|
||||
e = new ListSelectionEvent(this, firstIndex, lastIndex, isAdjusting);
|
||||
}
|
||||
((ListSelectionListener)listeners[i+1]).valueChanged(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fireValueChanged() {
|
||||
if (lastChangedIndex == MIN) {
|
||||
return;
|
||||
}
|
||||
/* Change the values before sending the event to the
|
||||
* listeners in case the event causes a listener to make
|
||||
* another change to the selection.
|
||||
*/
|
||||
int oldFirstChangedIndex = firstChangedIndex;
|
||||
int oldLastChangedIndex = lastChangedIndex;
|
||||
firstChangedIndex = MAX;
|
||||
lastChangedIndex = MIN;
|
||||
fireValueChanged(oldFirstChangedIndex, oldLastChangedIndex);
|
||||
}
|
||||
|
||||
|
||||
// Update first and last change indices
|
||||
private void markAsDirty(int r) {
|
||||
firstChangedIndex = Math.min(firstChangedIndex, r);
|
||||
lastChangedIndex = Math.max(lastChangedIndex, r);
|
||||
}
|
||||
|
||||
// Set the state at this index and update all relevant state.
|
||||
private void set(int r) {
|
||||
if (value.get(r)) {
|
||||
return;
|
||||
}
|
||||
value.set(r);
|
||||
Option option = (Option)get(r);
|
||||
option.setSelection(true);
|
||||
markAsDirty(r);
|
||||
|
||||
// Update minimum and maximum indices
|
||||
minIndex = Math.min(minIndex, r);
|
||||
maxIndex = Math.max(maxIndex, r);
|
||||
}
|
||||
|
||||
// Clear the state at this index and update all relevant state.
|
||||
private void clear(int r) {
|
||||
if (!value.get(r)) {
|
||||
return;
|
||||
}
|
||||
value.clear(r);
|
||||
Option option = (Option)get(r);
|
||||
option.setSelection(false);
|
||||
markAsDirty(r);
|
||||
|
||||
// Update minimum and maximum indices
|
||||
/*
|
||||
If (r > minIndex) the minimum has not changed.
|
||||
The case (r < minIndex) is not possible because r'th value was set.
|
||||
We only need to check for the case when lowest entry has been cleared,
|
||||
and in this case we need to search for the first value set above it.
|
||||
*/
|
||||
if (r == minIndex) {
|
||||
for(minIndex = minIndex + 1; minIndex <= maxIndex; minIndex++) {
|
||||
if (value.get(minIndex)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
If (r < maxIndex) the maximum has not changed.
|
||||
The case (r > maxIndex) is not possible because r'th value was set.
|
||||
We only need to check for the case when highest entry has been cleared,
|
||||
and in this case we need to search for the first value set below it.
|
||||
*/
|
||||
if (r == maxIndex) {
|
||||
for(maxIndex = maxIndex - 1; minIndex <= maxIndex; maxIndex--) {
|
||||
if (value.get(maxIndex)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Performance note: This method is called from inside a loop in
|
||||
changeSelection() but we will only iterate in the loops
|
||||
above on the basis of one iteration per deselected cell - in total.
|
||||
Ie. the next time this method is called the work of the previous
|
||||
deselection will not be repeated.
|
||||
|
||||
We also don't need to worry about the case when the min and max
|
||||
values are in their unassigned states. This cannot happen because
|
||||
this method's initial check ensures that the selection was not empty
|
||||
and therefore that the minIndex and maxIndex had 'real' values.
|
||||
|
||||
If we have cleared the whole selection, set the minIndex and maxIndex
|
||||
to their cannonical values so that the next set command always works
|
||||
just by using Math.min and Math.max.
|
||||
*/
|
||||
if (isSelectionEmpty()) {
|
||||
minIndex = MAX;
|
||||
maxIndex = MIN;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the leadAnchorNotificationEnabled flag.
|
||||
* @see #isLeadAnchorNotificationEnabled()
|
||||
*/
|
||||
public void setLeadAnchorNotificationEnabled(boolean flag) {
|
||||
leadAnchorNotificationEnabled = flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the leadAnchorNotificationEnabled flag.
|
||||
* When leadAnchorNotificationEnabled is true the model
|
||||
* generates notification events with bounds that cover all the changes to
|
||||
* the selection plus the changes to the lead and anchor indices.
|
||||
* Setting the flag to false causes a norrowing of the event's bounds to
|
||||
* include only the elements that have been selected or deselected since
|
||||
* the last change. Either way, the model continues to maintain the lead
|
||||
* and anchor variables internally. The default is true.
|
||||
* @return the value of the leadAnchorNotificationEnabled flag
|
||||
* @see #setLeadAnchorNotificationEnabled(boolean)
|
||||
*/
|
||||
public boolean isLeadAnchorNotificationEnabled() {
|
||||
return leadAnchorNotificationEnabled;
|
||||
}
|
||||
|
||||
private void updateLeadAnchorIndices(int anchorIndex, int leadIndex) {
|
||||
if (leadAnchorNotificationEnabled) {
|
||||
if (this.anchorIndex != anchorIndex) {
|
||||
if (this.anchorIndex != -1) { // The unassigned state.
|
||||
markAsDirty(this.anchorIndex);
|
||||
}
|
||||
markAsDirty(anchorIndex);
|
||||
}
|
||||
|
||||
if (this.leadIndex != leadIndex) {
|
||||
if (this.leadIndex != -1) { // The unassigned state.
|
||||
markAsDirty(this.leadIndex);
|
||||
}
|
||||
markAsDirty(leadIndex);
|
||||
}
|
||||
}
|
||||
this.anchorIndex = anchorIndex;
|
||||
this.leadIndex = leadIndex;
|
||||
}
|
||||
|
||||
private boolean contains(int a, int b, int i) {
|
||||
return (i >= a) && (i <= b);
|
||||
}
|
||||
|
||||
private void changeSelection(int clearMin, int clearMax,
|
||||
int setMin, int setMax, boolean clearFirst) {
|
||||
for(int i = Math.min(setMin, clearMin); i <= Math.max(setMax, clearMax); i++) {
|
||||
|
||||
boolean shouldClear = contains(clearMin, clearMax, i);
|
||||
boolean shouldSet = contains(setMin, setMax, i);
|
||||
|
||||
if (shouldSet && shouldClear) {
|
||||
if (clearFirst) {
|
||||
shouldClear = false;
|
||||
}
|
||||
else {
|
||||
shouldSet = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldSet) {
|
||||
set(i);
|
||||
}
|
||||
if (shouldClear) {
|
||||
clear(i);
|
||||
}
|
||||
}
|
||||
fireValueChanged();
|
||||
}
|
||||
|
||||
/* Change the selection with the effect of first clearing the values
|
||||
* in the inclusive range [clearMin, clearMax] then setting the values
|
||||
* in the inclusive range [setMin, setMax]. Do this in one pass so
|
||||
* that no values are cleared if they would later be set.
|
||||
*/
|
||||
private void changeSelection(int clearMin, int clearMax, int setMin, int setMax) {
|
||||
changeSelection(clearMin, clearMax, setMin, setMax, true);
|
||||
}
|
||||
|
||||
public void clearSelection() {
|
||||
removeSelectionInterval(minIndex, maxIndex);
|
||||
}
|
||||
|
||||
public void setSelectionInterval(int index0, int index1) {
|
||||
if (index0 == -1 || index1 == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getSelectionMode() == SINGLE_SELECTION) {
|
||||
index0 = index1;
|
||||
}
|
||||
|
||||
updateLeadAnchorIndices(index0, index1);
|
||||
|
||||
int clearMin = minIndex;
|
||||
int clearMax = maxIndex;
|
||||
int setMin = Math.min(index0, index1);
|
||||
int setMax = Math.max(index0, index1);
|
||||
changeSelection(clearMin, clearMax, setMin, setMax);
|
||||
}
|
||||
|
||||
public void addSelectionInterval(int index0, int index1)
|
||||
{
|
||||
if (index0 == -1 || index1 == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getSelectionMode() != MULTIPLE_INTERVAL_SELECTION) {
|
||||
setSelectionInterval(index0, index1);
|
||||
return;
|
||||
}
|
||||
|
||||
updateLeadAnchorIndices(index0, index1);
|
||||
|
||||
int clearMin = MAX;
|
||||
int clearMax = MIN;
|
||||
int setMin = Math.min(index0, index1);
|
||||
int setMax = Math.max(index0, index1);
|
||||
changeSelection(clearMin, clearMax, setMin, setMax);
|
||||
}
|
||||
|
||||
|
||||
public void removeSelectionInterval(int index0, int index1)
|
||||
{
|
||||
if (index0 == -1 || index1 == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateLeadAnchorIndices(index0, index1);
|
||||
|
||||
int clearMin = Math.min(index0, index1);
|
||||
int clearMax = Math.max(index0, index1);
|
||||
int setMin = MAX;
|
||||
int setMax = MIN;
|
||||
changeSelection(clearMin, clearMax, setMin, setMax);
|
||||
}
|
||||
|
||||
private void setState(int index, boolean state) {
|
||||
if (state) {
|
||||
set(index);
|
||||
}
|
||||
else {
|
||||
clear(index);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert length indices beginning before/after index. If the value
|
||||
* at index is itself selected, set all of the newly inserted
|
||||
* items, otherwise leave them unselected. This method is typically
|
||||
* called to sync the selection model with a corresponding change
|
||||
* in the data model.
|
||||
*/
|
||||
public void insertIndexInterval(int index, int length, boolean before)
|
||||
{
|
||||
/* The first new index will appear at insMinIndex and the last
|
||||
* one will appear at insMaxIndex
|
||||
*/
|
||||
int insMinIndex = (before) ? index : index + 1;
|
||||
int insMaxIndex = (insMinIndex + length) - 1;
|
||||
|
||||
/* Right shift the entire bitset by length, beginning with
|
||||
* index-1 if before is true, index+1 if it's false (i.e. with
|
||||
* insMinIndex).
|
||||
*/
|
||||
for(int i = maxIndex; i >= insMinIndex; i--) {
|
||||
setState(i + length, value.get(i));
|
||||
}
|
||||
|
||||
/* Initialize the newly inserted indices.
|
||||
*/
|
||||
boolean setInsertedValues = value.get(index);
|
||||
for(int i = insMinIndex; i <= insMaxIndex; i++) {
|
||||
setState(i, setInsertedValues);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove the indices in the interval index0,index1 (inclusive) from
|
||||
* the selection model. This is typically called to sync the selection
|
||||
* model width a corresponding change in the data model. Note
|
||||
* that (as always) index0 can be greater than index1.
|
||||
*/
|
||||
public void removeIndexInterval(int index0, int index1)
|
||||
{
|
||||
int rmMinIndex = Math.min(index0, index1);
|
||||
int rmMaxIndex = Math.max(index0, index1);
|
||||
int gapLength = (rmMaxIndex - rmMinIndex) + 1;
|
||||
|
||||
/* Shift the entire bitset to the left to close the index0, index1
|
||||
* gap.
|
||||
*/
|
||||
for(int i = rmMinIndex; i <= maxIndex; i++) {
|
||||
setState(i, value.get(i + gapLength));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setValueIsAdjusting(boolean isAdjusting) {
|
||||
if (isAdjusting != this.isAdjusting) {
|
||||
this.isAdjusting = isAdjusting;
|
||||
this.fireValueChanged(isAdjusting);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
String s = ((getValueIsAdjusting()) ? "~" : "=") + value.toString();
|
||||
return getClass().getName() + " " + Integer.toString(hashCode()) + " " + s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a clone of the receiver with the same selection.
|
||||
* <code>listenerLists</code> are not duplicated.
|
||||
*
|
||||
* @return a clone of the receiver
|
||||
* @exception CloneNotSupportedException if the receiver does not
|
||||
* both (a) implement the <code>Cloneable</code> interface
|
||||
* and (b) define a <code>clone</code> method
|
||||
*/
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
OptionListModel clone = (OptionListModel)super.clone();
|
||||
clone.value = (BitSet)value.clone();
|
||||
clone.listenerList = new EventListenerList();
|
||||
return clone;
|
||||
}
|
||||
|
||||
public int getAnchorSelectionIndex() {
|
||||
return anchorIndex;
|
||||
}
|
||||
|
||||
public int getLeadSelectionIndex() {
|
||||
return leadIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the anchor selection index, leaving all selection values unchanged.
|
||||
*
|
||||
* @see #getAnchorSelectionIndex
|
||||
* @see #setLeadSelectionIndex
|
||||
*/
|
||||
public void setAnchorSelectionIndex(int anchorIndex) {
|
||||
this.anchorIndex = anchorIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the lead selection index, ensuring that values between the
|
||||
* anchor and the new lead are either all selected or all deselected.
|
||||
* If the value at the anchor index is selected, first clear all the
|
||||
* values in the range [anchor, oldLeadIndex], then select all the values
|
||||
* values in the range [anchor, newLeadIndex], where oldLeadIndex is the old
|
||||
* leadIndex and newLeadIndex is the new one.
|
||||
* <p>
|
||||
* If the value at the anchor index is not selected, do the same thing in reverse,
|
||||
* selecting values in the old range and deselecting values in the new one.
|
||||
* <p>
|
||||
* Generate a single event for this change and notify all listeners.
|
||||
* For the purposes of generating minimal bounds in this event, do the
|
||||
* operation in a single pass; that way the first and last index inside the
|
||||
* ListSelectionEvent that is broadcast will refer to cells that actually
|
||||
* changed value because of this method. If, instead, this operation were
|
||||
* done in two steps the effect on the selection state would be the same
|
||||
* but two events would be generated and the bounds around the changed values
|
||||
* would be wider, including cells that had been first cleared and only
|
||||
* to later be set.
|
||||
* <p>
|
||||
* This method can be used in the mouseDragged() method of a UI class
|
||||
* to extend a selection.
|
||||
*
|
||||
* @see #getLeadSelectionIndex
|
||||
* @see #setAnchorSelectionIndex
|
||||
*/
|
||||
public void setLeadSelectionIndex(int leadIndex) {
|
||||
int anchorIndex = this.anchorIndex;
|
||||
if (getSelectionMode() == SINGLE_SELECTION) {
|
||||
anchorIndex = leadIndex;
|
||||
}
|
||||
|
||||
int oldMin = Math.min(this.anchorIndex, this.leadIndex);
|
||||
int oldMax = Math.max(this.anchorIndex, this.leadIndex);
|
||||
int newMin = Math.min(anchorIndex, leadIndex);
|
||||
int newMax = Math.max(anchorIndex, leadIndex);
|
||||
if (value.get(this.anchorIndex)) {
|
||||
changeSelection(oldMin, oldMax, newMin, newMax);
|
||||
}
|
||||
else {
|
||||
changeSelection(newMin, newMax, oldMin, oldMax, false);
|
||||
}
|
||||
this.anchorIndex = anchorIndex;
|
||||
this.leadIndex = leadIndex;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is responsible for storing the state
|
||||
* of the initial selection. If the selectionMode
|
||||
* is the default, i.e allowing only for SINGLE_SELECTION,
|
||||
* then the very last OPTION that has the selected
|
||||
* attribute set wins.
|
||||
*/
|
||||
public void setInitialSelection(int i) {
|
||||
if (initialValue.get(i)) {
|
||||
return;
|
||||
}
|
||||
if (selectionMode == SINGLE_SELECTION) {
|
||||
// reset to empty
|
||||
initialValue.and(new BitSet());
|
||||
}
|
||||
initialValue.set(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the BitSet that represents the initial
|
||||
* set of selected items in the list.
|
||||
*/
|
||||
public BitSet getInitialSelection() {
|
||||
return initialValue;
|
||||
}
|
||||
}
|
||||
294
jdkSrc/jdk8/javax/swing/text/html/ParagraphView.java
Normal file
294
jdkSrc/jdk8/javax/swing/text/html/ParagraphView.java
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import java.awt.*;
|
||||
import javax.swing.SizeRequirements;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.text.Document;
|
||||
import javax.swing.text.Element;
|
||||
import javax.swing.text.AttributeSet;
|
||||
import javax.swing.text.StyleConstants;
|
||||
import javax.swing.text.View;
|
||||
import javax.swing.text.ViewFactory;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.JTextComponent;
|
||||
|
||||
/**
|
||||
* Displays the a paragraph, and uses css attributes for its
|
||||
* configuration.
|
||||
*
|
||||
* @author Timothy Prinzing
|
||||
*/
|
||||
|
||||
public class ParagraphView extends javax.swing.text.ParagraphView {
|
||||
|
||||
/**
|
||||
* Constructs a ParagraphView for the given element.
|
||||
*
|
||||
* @param elem the element that this view is responsible for
|
||||
*/
|
||||
public ParagraphView(Element elem) {
|
||||
super(elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the parent view for this view. This is
|
||||
* guaranteed to be called before any other methods if the
|
||||
* parent view is functioning properly.
|
||||
* <p>
|
||||
* This is implemented
|
||||
* to forward to the superclass as well as call the
|
||||
* {@link #setPropertiesFromAttributes setPropertiesFromAttributes}
|
||||
* method to set the paragraph properties from the css
|
||||
* attributes. The call is made at this time to ensure
|
||||
* the ability to resolve upward through the parents
|
||||
* view attributes.
|
||||
*
|
||||
* @param parent the new parent, or null if the view is
|
||||
* being removed from a parent it was previously added
|
||||
* to
|
||||
*/
|
||||
public void setParent(View parent) {
|
||||
super.setParent(parent);
|
||||
if (parent != null) {
|
||||
setPropertiesFromAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the attributes to use when rendering. This is
|
||||
* implemented to multiplex the attributes specified in the
|
||||
* model with a StyleSheet.
|
||||
*/
|
||||
public AttributeSet getAttributes() {
|
||||
if (attr == null) {
|
||||
StyleSheet sheet = getStyleSheet();
|
||||
attr = sheet.getViewAttributes(this);
|
||||
}
|
||||
return attr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the paragraph from css attributes instead of
|
||||
* the values found in StyleConstants (i.e. which are used
|
||||
* by the superclass). Since
|
||||
*/
|
||||
protected void setPropertiesFromAttributes() {
|
||||
StyleSheet sheet = getStyleSheet();
|
||||
attr = sheet.getViewAttributes(this);
|
||||
painter = sheet.getBoxPainter(attr);
|
||||
if (attr != null) {
|
||||
super.setPropertiesFromAttributes();
|
||||
setInsets((short) painter.getInset(TOP, this),
|
||||
(short) painter.getInset(LEFT, this),
|
||||
(short) painter.getInset(BOTTOM, this),
|
||||
(short) painter.getInset(RIGHT, this));
|
||||
Object o = attr.getAttribute(CSS.Attribute.TEXT_ALIGN);
|
||||
if (o != null) {
|
||||
// set horizontal alignment
|
||||
String ta = o.toString();
|
||||
if (ta.equals("left")) {
|
||||
setJustification(StyleConstants.ALIGN_LEFT);
|
||||
} else if (ta.equals("center")) {
|
||||
setJustification(StyleConstants.ALIGN_CENTER);
|
||||
} else if (ta.equals("right")) {
|
||||
setJustification(StyleConstants.ALIGN_RIGHT);
|
||||
} else if (ta.equals("justify")) {
|
||||
setJustification(StyleConstants.ALIGN_JUSTIFIED);
|
||||
}
|
||||
}
|
||||
// Get the width/height
|
||||
cssWidth = (CSS.LengthValue)attr.getAttribute(
|
||||
CSS.Attribute.WIDTH);
|
||||
cssHeight = (CSS.LengthValue)attr.getAttribute(
|
||||
CSS.Attribute.HEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
protected StyleSheet getStyleSheet() {
|
||||
HTMLDocument doc = (HTMLDocument) getDocument();
|
||||
return doc.getStyleSheet();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the needs for the paragraph along the minor axis.
|
||||
*
|
||||
* <p>If size requirements are explicitly specified for the paragraph,
|
||||
* use that requirements. Otherwise, use the requirements of the
|
||||
* superclass {@link javax.swing.text.ParagraphView}.</p>
|
||||
*
|
||||
* <p>If the {@code axis} parameter is neither {@code View.X_AXIS} nor
|
||||
* {@code View.Y_AXIS}, {@link IllegalArgumentException} is thrown. If the
|
||||
* {@code r} parameter is {@code null,} a new {@code SizeRequirements}
|
||||
* object is created, otherwise the supplied {@code SizeRequirements}
|
||||
* object is returned.</p>
|
||||
*
|
||||
* @param axis the minor axis
|
||||
* @param r the input {@code SizeRequirements} object
|
||||
* @return the new or adjusted {@code SizeRequirements} object
|
||||
* @throws IllegalArgumentException if the {@code axis} parameter is invalid
|
||||
*/
|
||||
protected SizeRequirements calculateMinorAxisRequirements(
|
||||
int axis, SizeRequirements r) {
|
||||
r = super.calculateMinorAxisRequirements(axis, r);
|
||||
|
||||
if (BlockView.spanSetFromAttributes(axis, r, cssWidth, cssHeight)) {
|
||||
// Offset by the margins so that pref/min/max return the
|
||||
// right value.
|
||||
int margin = (axis == X_AXIS) ? getLeftInset() + getRightInset() :
|
||||
getTopInset() + getBottomInset();
|
||||
r.minimum -= margin;
|
||||
r.preferred -= margin;
|
||||
r.maximum -= margin;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indicates whether or not this view should be
|
||||
* displayed. If none of the children wish to be
|
||||
* displayed and the only visible child is the
|
||||
* break that ends the paragraph, the paragraph
|
||||
* will not be considered visible. Otherwise,
|
||||
* it will be considered visible and return true.
|
||||
*
|
||||
* @return true if the paragraph should be displayed
|
||||
*/
|
||||
public boolean isVisible() {
|
||||
|
||||
int n = getLayoutViewCount() - 1;
|
||||
for (int i = 0; i < n; i++) {
|
||||
View v = getLayoutView(i);
|
||||
if (v.isVisible()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (n > 0) {
|
||||
View v = getLayoutView(n);
|
||||
if ((v.getEndOffset() - v.getStartOffset()) == 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// If it's the last paragraph and not editable, it shouldn't
|
||||
// be visible.
|
||||
if (getStartOffset() == getDocument().getLength()) {
|
||||
boolean editable = false;
|
||||
Component c = getContainer();
|
||||
if (c instanceof JTextComponent) {
|
||||
editable = ((JTextComponent)c).isEditable();
|
||||
}
|
||||
if (!editable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders using the given rendering surface and area on that
|
||||
* surface. This is implemented to delegate to the superclass
|
||||
* after stashing the base coordinate for tab calculations.
|
||||
*
|
||||
* @param g the rendering surface to use
|
||||
* @param a the allocated region to render into
|
||||
* @see View#paint
|
||||
*/
|
||||
public void paint(Graphics g, Shape a) {
|
||||
if (a == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Rectangle r;
|
||||
if (a instanceof Rectangle) {
|
||||
r = (Rectangle) a;
|
||||
} else {
|
||||
r = a.getBounds();
|
||||
}
|
||||
painter.paint(g, r.x, r.y, r.width, r.height, this);
|
||||
super.paint(g, a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the preferred span for this view. Returns
|
||||
* 0 if the view is not visible, otherwise it calls the
|
||||
* superclass method to get the preferred span.
|
||||
* axis.
|
||||
*
|
||||
* @param axis may be either View.X_AXIS or View.Y_AXIS
|
||||
* @return the span the view would like to be rendered into;
|
||||
* typically the view is told to render into the span
|
||||
* that is returned, although there is no guarantee;
|
||||
* the parent may choose to resize or break the view
|
||||
* @see javax.swing.text.ParagraphView#getPreferredSpan
|
||||
*/
|
||||
public float getPreferredSpan(int axis) {
|
||||
if (!isVisible()) {
|
||||
return 0;
|
||||
}
|
||||
return super.getPreferredSpan(axis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the minimum span for this view along an
|
||||
* axis. Returns 0 if the view is not visible, otherwise
|
||||
* it calls the superclass method to get the minimum span.
|
||||
*
|
||||
* @param axis may be either <code>View.X_AXIS</code> or
|
||||
* <code>View.Y_AXIS</code>
|
||||
* @return the minimum span the view can be rendered into
|
||||
* @see javax.swing.text.ParagraphView#getMinimumSpan
|
||||
*/
|
||||
public float getMinimumSpan(int axis) {
|
||||
if (!isVisible()) {
|
||||
return 0;
|
||||
}
|
||||
return super.getMinimumSpan(axis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the maximum span for this view along an
|
||||
* axis. Returns 0 if the view is not visible, otherwise
|
||||
* it calls the superclass method ot get the maximum span.
|
||||
*
|
||||
* @param axis may be either <code>View.X_AXIS</code> or
|
||||
* <code>View.Y_AXIS</code>
|
||||
* @return the maximum span the view can be rendered into
|
||||
* @see javax.swing.text.ParagraphView#getMaximumSpan
|
||||
*/
|
||||
public float getMaximumSpan(int axis) {
|
||||
if (!isVisible()) {
|
||||
return 0;
|
||||
}
|
||||
return super.getMaximumSpan(axis);
|
||||
}
|
||||
|
||||
private AttributeSet attr;
|
||||
private StyleSheet.BoxPainter painter;
|
||||
private CSS.LengthValue cssWidth;
|
||||
private CSS.LengthValue cssHeight;
|
||||
}
|
||||
3338
jdkSrc/jdk8/javax/swing/text/html/StyleSheet.java
Normal file
3338
jdkSrc/jdk8/javax/swing/text/html/StyleSheet.java
Normal file
File diff suppressed because it is too large
Load Diff
1801
jdkSrc/jdk8/javax/swing/text/html/TableView.java
Normal file
1801
jdkSrc/jdk8/javax/swing/text/html/TableView.java
Normal file
File diff suppressed because it is too large
Load Diff
68
jdkSrc/jdk8/javax/swing/text/html/TextAreaDocument.java
Normal file
68
jdkSrc/jdk8/javax/swing/text/html/TextAreaDocument.java
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html;
|
||||
|
||||
import javax.swing.text.*;
|
||||
|
||||
|
||||
/**
|
||||
* TextAreaDocument extends the capabilities of the PlainDocument
|
||||
* to store the data that is initially set in the Document.
|
||||
* This is stored in order to enable an accurate reset of the
|
||||
* state when a reset is requested.
|
||||
*
|
||||
* @author Sunita Mani
|
||||
*/
|
||||
|
||||
class TextAreaDocument extends PlainDocument {
|
||||
|
||||
String initialText;
|
||||
|
||||
|
||||
/**
|
||||
* Resets the model by removing all the data,
|
||||
* and restoring it to its initial state.
|
||||
*/
|
||||
void reset() {
|
||||
try {
|
||||
remove(0, getLength());
|
||||
if (initialText != null) {
|
||||
insertString(0, initialText, null);
|
||||
}
|
||||
} catch (BadLocationException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the data that the model is initially
|
||||
* loaded with.
|
||||
*/
|
||||
void storeInitialText() {
|
||||
try {
|
||||
initialText = getText(0, getLength());
|
||||
} catch (BadLocationException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
172
jdkSrc/jdk8/javax/swing/text/html/parser/AttributeList.java
Normal file
172
jdkSrc/jdk8/javax/swing/text/html/parser/AttributeList.java
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.text.html.parser;
|
||||
|
||||
import java.util.Vector;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Enumeration;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* This class defines the attributes of an SGML element
|
||||
* as described in a DTD using the ATTLIST construct.
|
||||
* An AttributeList can be obtained from the Element
|
||||
* class using the getAttributes() method.
|
||||
* <p>
|
||||
* It is actually an element in a linked list. Use the
|
||||
* getNext() method repeatedly to enumerate all the attributes
|
||||
* of an element.
|
||||
*
|
||||
* @see Element
|
||||
* @author Arthur Van Hoff
|
||||
*
|
||||
*/
|
||||
public final
|
||||
class AttributeList implements DTDConstants, Serializable {
|
||||
public String name;
|
||||
public int type;
|
||||
public Vector<?> values;
|
||||
public int modifier;
|
||||
public String value;
|
||||
public AttributeList next;
|
||||
|
||||
AttributeList() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an attribute list element.
|
||||
*/
|
||||
public AttributeList(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an attribute list element.
|
||||
*/
|
||||
public AttributeList(String name, int type, int modifier, String value, Vector<?> values, AttributeList next) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.modifier = modifier;
|
||||
this.value = value;
|
||||
this.values = values;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return attribute name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return attribute type
|
||||
* @see DTDConstants
|
||||
*/
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return attribute modifier
|
||||
* @see DTDConstants
|
||||
*/
|
||||
public int getModifier() {
|
||||
return modifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return possible attribute values
|
||||
*/
|
||||
public Enumeration<?> getValues() {
|
||||
return (values != null) ? values.elements() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return default attribute value
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the next attribute in the list
|
||||
*/
|
||||
public AttributeList getNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string representation
|
||||
*/
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a hashtable of attribute types.
|
||||
*/
|
||||
static Hashtable<Object, Object> attributeTypes = new Hashtable<Object, Object>();
|
||||
|
||||
static void defineAttributeType(String nm, int val) {
|
||||
Integer num = Integer.valueOf(val);
|
||||
attributeTypes.put(nm, num);
|
||||
attributeTypes.put(num, nm);
|
||||
}
|
||||
|
||||
static {
|
||||
defineAttributeType("CDATA", CDATA);
|
||||
defineAttributeType("ENTITY", ENTITY);
|
||||
defineAttributeType("ENTITIES", ENTITIES);
|
||||
defineAttributeType("ID", ID);
|
||||
defineAttributeType("IDREF", IDREF);
|
||||
defineAttributeType("IDREFS", IDREFS);
|
||||
defineAttributeType("NAME", NAME);
|
||||
defineAttributeType("NAMES", NAMES);
|
||||
defineAttributeType("NMTOKEN", NMTOKEN);
|
||||
defineAttributeType("NMTOKENS", NMTOKENS);
|
||||
defineAttributeType("NOTATION", NOTATION);
|
||||
defineAttributeType("NUMBER", NUMBER);
|
||||
defineAttributeType("NUMBERS", NUMBERS);
|
||||
defineAttributeType("NUTOKEN", NUTOKEN);
|
||||
defineAttributeType("NUTOKENS", NUTOKENS);
|
||||
|
||||
attributeTypes.put("fixed", Integer.valueOf(FIXED));
|
||||
attributeTypes.put("required", Integer.valueOf(REQUIRED));
|
||||
attributeTypes.put("current", Integer.valueOf(CURRENT));
|
||||
attributeTypes.put("conref", Integer.valueOf(CONREF));
|
||||
attributeTypes.put("implied", Integer.valueOf(IMPLIED));
|
||||
}
|
||||
|
||||
public static int name2type(String nm) {
|
||||
Integer i = (Integer)attributeTypes.get(nm);
|
||||
return (i == null) ? CDATA : i.intValue();
|
||||
}
|
||||
|
||||
public static String type2name(int tp) {
|
||||
return (String)attributeTypes.get(Integer.valueOf(tp));
|
||||
}
|
||||
}
|
||||
254
jdkSrc/jdk8/javax/swing/text/html/parser/ContentModel.java
Normal file
254
jdkSrc/jdk8/javax/swing/text/html/parser/ContentModel.java
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.text.html.parser;
|
||||
|
||||
import java.util.Vector;
|
||||
import java.util.Enumeration;
|
||||
import java.io.*;
|
||||
|
||||
|
||||
/**
|
||||
* A representation of a content model. A content model is
|
||||
* basically a restricted BNF expression. It is restricted in
|
||||
* the sense that it must be deterministic. This means that you
|
||||
* don't have to represent it as a finite state automaton.<p>
|
||||
* See Annex H on page 556 of the SGML handbook for more information.
|
||||
*
|
||||
* @author Arthur van Hoff
|
||||
*
|
||||
*/
|
||||
public final class ContentModel implements Serializable {
|
||||
/**
|
||||
* Type. Either '*', '?', '+', ',', '|', '&'.
|
||||
*/
|
||||
public int type;
|
||||
|
||||
/**
|
||||
* The content. Either an Element or a ContentModel.
|
||||
*/
|
||||
public Object content;
|
||||
|
||||
/**
|
||||
* The next content model (in a ',', '|' or '&' expression).
|
||||
*/
|
||||
public ContentModel next;
|
||||
|
||||
public ContentModel() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a content model for an element.
|
||||
*/
|
||||
public ContentModel(Element content) {
|
||||
this(0, content, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a content model of a particular type.
|
||||
*/
|
||||
public ContentModel(int type, ContentModel content) {
|
||||
this(type, content, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a content model of a particular type.
|
||||
*/
|
||||
public ContentModel(int type, Object content, ContentModel next) {
|
||||
this.type = type;
|
||||
this.content = content;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the content model could
|
||||
* match an empty input stream.
|
||||
*/
|
||||
public boolean empty() {
|
||||
switch (type) {
|
||||
case '*':
|
||||
case '?':
|
||||
return true;
|
||||
|
||||
case '+':
|
||||
case '|':
|
||||
for (ContentModel m = (ContentModel)content ; m != null ; m = m.next) {
|
||||
if (m.empty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
case ',':
|
||||
case '&':
|
||||
for (ContentModel m = (ContentModel)content ; m != null ; m = m.next) {
|
||||
if (!m.empty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update elemVec with the list of elements that are
|
||||
* part of the this contentModel.
|
||||
*/
|
||||
public void getElements(Vector<Element> elemVec) {
|
||||
switch (type) {
|
||||
case '*':
|
||||
case '?':
|
||||
case '+':
|
||||
((ContentModel)content).getElements(elemVec);
|
||||
break;
|
||||
case ',':
|
||||
case '|':
|
||||
case '&':
|
||||
for (ContentModel m=(ContentModel)content; m != null; m=m.next){
|
||||
m.getElements(elemVec);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
elemVec.addElement((Element)content);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean valSet[];
|
||||
private boolean val[];
|
||||
// A cache used by first(). This cache was found to speed parsing
|
||||
// by about 10% (based on measurements of the 4-12 code base after
|
||||
// buffering was fixed).
|
||||
|
||||
/**
|
||||
* Return true if the token could potentially be the
|
||||
* first token in the input stream.
|
||||
*/
|
||||
public boolean first(Object token) {
|
||||
switch (type) {
|
||||
case '*':
|
||||
case '?':
|
||||
case '+':
|
||||
return ((ContentModel)content).first(token);
|
||||
|
||||
case ',':
|
||||
for (ContentModel m = (ContentModel)content ; m != null ; m = m.next) {
|
||||
if (m.first(token)) {
|
||||
return true;
|
||||
}
|
||||
if (!m.empty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
case '|':
|
||||
case '&': {
|
||||
Element e = (Element) token;
|
||||
if (valSet == null || valSet.length <= Element.getMaxIndex()) {
|
||||
valSet = new boolean[Element.getMaxIndex() + 1];
|
||||
val = new boolean[valSet.length];
|
||||
}
|
||||
if (valSet[e.index]) {
|
||||
return val[e.index];
|
||||
}
|
||||
for (ContentModel m = (ContentModel)content ; m != null ; m = m.next) {
|
||||
if (m.first(token)) {
|
||||
val[e.index] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
valSet[e.index] = true;
|
||||
return val[e.index];
|
||||
}
|
||||
|
||||
default:
|
||||
return (content == token);
|
||||
// PENDING: refer to comment in ContentModelState
|
||||
/*
|
||||
if (content == token) {
|
||||
return true;
|
||||
}
|
||||
Element e = (Element)content;
|
||||
if (e.omitStart() && e.content != null) {
|
||||
return e.content.first(token);
|
||||
}
|
||||
return false;
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the element that must be next.
|
||||
*/
|
||||
public Element first() {
|
||||
switch (type) {
|
||||
case '&':
|
||||
case '|':
|
||||
case '*':
|
||||
case '?':
|
||||
return null;
|
||||
|
||||
case '+':
|
||||
case ',':
|
||||
return ((ContentModel)content).first();
|
||||
|
||||
default:
|
||||
return (Element)content;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to a string.
|
||||
*/
|
||||
public String toString() {
|
||||
switch (type) {
|
||||
case '*':
|
||||
return content + "*";
|
||||
case '?':
|
||||
return content + "?";
|
||||
case '+':
|
||||
return content + "+";
|
||||
|
||||
case ',':
|
||||
case '|':
|
||||
case '&':
|
||||
char data[] = {' ', (char)type, ' '};
|
||||
String str = "";
|
||||
for (ContentModel m = (ContentModel)content ; m != null ; m = m.next) {
|
||||
str = str + m;
|
||||
if (m.next != null) {
|
||||
str += new String(data);
|
||||
}
|
||||
}
|
||||
return "(" + str + ")";
|
||||
|
||||
default:
|
||||
return content.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
295
jdkSrc/jdk8/javax/swing/text/html/parser/ContentModelState.java
Normal file
295
jdkSrc/jdk8/javax/swing/text/html/parser/ContentModelState.java
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2000, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.text.html.parser;
|
||||
|
||||
/**
|
||||
* A content model state. This is basically a list of pointers to
|
||||
* the BNF expression representing the model (the ContentModel).
|
||||
* Each element in a DTD has a content model which describes the
|
||||
* elements that may occur inside, and the order in which they can
|
||||
* occur.
|
||||
* <p>
|
||||
* Each time a token is reduced a new state is created.
|
||||
* <p>
|
||||
* See Annex H on page 556 of the SGML handbook for more information.
|
||||
*
|
||||
* @see Parser
|
||||
* @see DTD
|
||||
* @see Element
|
||||
* @see ContentModel
|
||||
* @author Arthur van Hoff
|
||||
*/
|
||||
class ContentModelState {
|
||||
ContentModel model;
|
||||
long value;
|
||||
ContentModelState next;
|
||||
|
||||
/**
|
||||
* Create a content model state for a content model.
|
||||
*/
|
||||
public ContentModelState(ContentModel model) {
|
||||
this(model, null, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a content model state for a content model given the
|
||||
* remaining state that needs to be reduce.
|
||||
*/
|
||||
ContentModelState(Object content, ContentModelState next) {
|
||||
this(content, next, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a content model state for a content model given the
|
||||
* remaining state that needs to be reduce.
|
||||
*/
|
||||
ContentModelState(Object content, ContentModelState next, long value) {
|
||||
this.model = (ContentModel)content;
|
||||
this.next = next;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the content model that is relevant to the current state.
|
||||
*/
|
||||
public ContentModel getModel() {
|
||||
ContentModel m = model;
|
||||
for (int i = 0; i < value; i++) {
|
||||
if (m.next != null) {
|
||||
m = m.next;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the state can be terminated. That is there are no more
|
||||
* tokens required in the input stream.
|
||||
* @return true if the model can terminate without further input
|
||||
*/
|
||||
public boolean terminate() {
|
||||
switch (model.type) {
|
||||
case '+':
|
||||
if ((value == 0) && !(model).empty()) {
|
||||
return false;
|
||||
}
|
||||
case '*':
|
||||
case '?':
|
||||
return (next == null) || next.terminate();
|
||||
|
||||
case '|':
|
||||
for (ContentModel m = (ContentModel)model.content ; m != null ; m = m.next) {
|
||||
if (m.empty()) {
|
||||
return (next == null) || next.terminate();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
case '&': {
|
||||
ContentModel m = (ContentModel)model.content;
|
||||
|
||||
for (int i = 0 ; m != null ; i++, m = m.next) {
|
||||
if ((value & (1L << i)) == 0) {
|
||||
if (!m.empty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (next == null) || next.terminate();
|
||||
}
|
||||
|
||||
case ',': {
|
||||
ContentModel m = (ContentModel)model.content;
|
||||
for (int i = 0 ; i < value ; i++, m = m.next);
|
||||
|
||||
for (; (m != null) && m.empty() ; m = m.next);
|
||||
if (m != null) {
|
||||
return false;
|
||||
}
|
||||
return (next == null) || next.terminate();
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the state can be terminated. That is there are no more
|
||||
* tokens required in the input stream.
|
||||
* @return the only possible element that can occur next
|
||||
*/
|
||||
public Element first() {
|
||||
switch (model.type) {
|
||||
case '*':
|
||||
case '?':
|
||||
case '|':
|
||||
case '&':
|
||||
return null;
|
||||
|
||||
case '+':
|
||||
return model.first();
|
||||
|
||||
case ',': {
|
||||
ContentModel m = (ContentModel)model.content;
|
||||
for (int i = 0 ; i < value ; i++, m = m.next);
|
||||
return m.first();
|
||||
}
|
||||
|
||||
default:
|
||||
return model.first();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance this state to a new state. An exception is thrown if the
|
||||
* token is illegal at this point in the content model.
|
||||
* @return next state after reducing a token
|
||||
*/
|
||||
public ContentModelState advance(Object token) {
|
||||
switch (model.type) {
|
||||
case '+':
|
||||
if (model.first(token)) {
|
||||
return new ContentModelState(model.content,
|
||||
new ContentModelState(model, next, value + 1)).advance(token);
|
||||
}
|
||||
if (value != 0) {
|
||||
if (next != null) {
|
||||
return next.advance(token);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case '*':
|
||||
if (model.first(token)) {
|
||||
return new ContentModelState(model.content, this).advance(token);
|
||||
}
|
||||
if (next != null) {
|
||||
return next.advance(token);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
case '?':
|
||||
if (model.first(token)) {
|
||||
return new ContentModelState(model.content, next).advance(token);
|
||||
}
|
||||
if (next != null) {
|
||||
return next.advance(token);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
case '|':
|
||||
for (ContentModel m = (ContentModel)model.content ; m != null ; m = m.next) {
|
||||
if (m.first(token)) {
|
||||
return new ContentModelState(m, next).advance(token);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ',': {
|
||||
ContentModel m = (ContentModel)model.content;
|
||||
for (int i = 0 ; i < value ; i++, m = m.next);
|
||||
|
||||
if (m.first(token) || m.empty()) {
|
||||
if (m.next == null) {
|
||||
return new ContentModelState(m, next).advance(token);
|
||||
} else {
|
||||
return new ContentModelState(m,
|
||||
new ContentModelState(model, next, value + 1)).advance(token);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case '&': {
|
||||
ContentModel m = (ContentModel)model.content;
|
||||
boolean complete = true;
|
||||
|
||||
for (int i = 0 ; m != null ; i++, m = m.next) {
|
||||
if ((value & (1L << i)) == 0) {
|
||||
if (m.first(token)) {
|
||||
return new ContentModelState(m,
|
||||
new ContentModelState(model, next, value | (1L << i))).advance(token);
|
||||
}
|
||||
if (!m.empty()) {
|
||||
complete = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (complete) {
|
||||
if (next != null) {
|
||||
return next.advance(token);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (model.content == token) {
|
||||
if (next == null && (token instanceof Element) &&
|
||||
((Element)token).content != null) {
|
||||
return new ContentModelState(((Element)token).content);
|
||||
}
|
||||
return next;
|
||||
}
|
||||
// PENDING: Currently we don't correctly deal with optional start
|
||||
// tags. This can most notably be seen with the 4.01 spec where
|
||||
// TBODY's start and end tags are optional.
|
||||
// Uncommenting this and the PENDING in ContentModel will
|
||||
// correctly skip the omit tags, but the delegate is not notified.
|
||||
// Some additional API needs to be added to track skipped tags,
|
||||
// and this can then be added back.
|
||||
/*
|
||||
if ((model.content instanceof Element)) {
|
||||
Element e = (Element)model.content;
|
||||
|
||||
if (e.omitStart() && e.content != null) {
|
||||
return new ContentModelState(e.content, next).advance(
|
||||
token);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// We used to throw this exception at this point. However, it
|
||||
// was determined that throwing this exception was more expensive
|
||||
// than returning null, and we could not justify to ourselves why
|
||||
// it was necessary to throw an exception, rather than simply
|
||||
// returning null. I'm leaving it in a commented out state so
|
||||
// that it can be easily restored if the situation ever arises.
|
||||
//
|
||||
// throw new IllegalArgumentException("invalid token: " + token);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
466
jdkSrc/jdk8/javax/swing/text/html/parser/DTD.java
Normal file
466
jdkSrc/jdk8/javax/swing/text/html/parser/DTD.java
Normal file
@@ -0,0 +1,466 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.text.html.parser;
|
||||
|
||||
import sun.awt.AppContext;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
import java.util.BitSet;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Properties;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* The representation of an SGML DTD. DTD describes a document
|
||||
* syntax and is used in parsing of HTML documents. It contains
|
||||
* a list of elements and their attributes as well as a list of
|
||||
* entities defined in the DTD.
|
||||
*
|
||||
* @see Element
|
||||
* @see AttributeList
|
||||
* @see ContentModel
|
||||
* @see Parser
|
||||
* @author Arthur van Hoff
|
||||
*/
|
||||
public
|
||||
class DTD implements DTDConstants {
|
||||
public String name;
|
||||
public Vector<Element> elements = new Vector<Element>();
|
||||
public Hashtable<String,Element> elementHash
|
||||
= new Hashtable<String,Element>();
|
||||
public Hashtable<Object,Entity> entityHash
|
||||
= new Hashtable<Object,Entity>();
|
||||
public final Element pcdata = getElement("#pcdata");
|
||||
public final Element html = getElement("html");
|
||||
public final Element meta = getElement("meta");
|
||||
public final Element base = getElement("base");
|
||||
public final Element isindex = getElement("isindex");
|
||||
public final Element head = getElement("head");
|
||||
public final Element body = getElement("body");
|
||||
public final Element applet = getElement("applet");
|
||||
public final Element param = getElement("param");
|
||||
public final Element p = getElement("p");
|
||||
public final Element title = getElement("title");
|
||||
final Element style = getElement("style");
|
||||
final Element link = getElement("link");
|
||||
final Element script = getElement("script");
|
||||
|
||||
public static final int FILE_VERSION = 1;
|
||||
|
||||
/**
|
||||
* Creates a new DTD with the specified name.
|
||||
* @param name the name, as a <code>String</code> of the new DTD
|
||||
*/
|
||||
protected DTD(String name) {
|
||||
this.name = name;
|
||||
defEntity("#RE", GENERAL, '\r');
|
||||
defEntity("#RS", GENERAL, '\n');
|
||||
defEntity("#SPACE", GENERAL, ' ');
|
||||
defineElement("unknown", EMPTY, false, true, null, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the DTD.
|
||||
* @return the name of the DTD
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an entity by name.
|
||||
* @return the <code>Entity</code> corresponding to the
|
||||
* <code>name</code> <code>String</code>
|
||||
*/
|
||||
public Entity getEntity(String name) {
|
||||
return entityHash.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a character entity.
|
||||
* @return the <code>Entity</code> corresponding to the
|
||||
* <code>ch</code> character
|
||||
*/
|
||||
public Entity getEntity(int ch) {
|
||||
return entityHash.get(Integer.valueOf(ch));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the element is part of the DTD,
|
||||
* otherwise returns <code>false</code>.
|
||||
*
|
||||
* @param name the requested <code>String</code>
|
||||
* @return <code>true</code> if <code>name</code> exists as
|
||||
* part of the DTD, otherwise returns <code>false</code>
|
||||
*/
|
||||
boolean elementExists(String name) {
|
||||
return !"unknown".equals(name) && (elementHash.get(name) != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an element by name. A new element is
|
||||
* created if the element doesn't exist.
|
||||
*
|
||||
* @param name the requested <code>String</code>
|
||||
* @return the <code>Element</code> corresponding to
|
||||
* <code>name</code>, which may be newly created
|
||||
*/
|
||||
public Element getElement(String name) {
|
||||
Element e = elementHash.get(name);
|
||||
if (e == null) {
|
||||
e = new Element(name, elements.size());
|
||||
elements.addElement(e);
|
||||
elementHash.put(name, e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an element by index.
|
||||
*
|
||||
* @param index the requested index
|
||||
* @return the <code>Element</code> corresponding to
|
||||
* <code>index</code>
|
||||
*/
|
||||
public Element getElement(int index) {
|
||||
return elements.elementAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines an entity. If the <code>Entity</code> specified
|
||||
* by <code>name</code>, <code>type</code>, and <code>data</code>
|
||||
* exists, it is returned; otherwise a new <code>Entity</code>
|
||||
* is created and is returned.
|
||||
*
|
||||
* @param name the name of the <code>Entity</code> as a <code>String</code>
|
||||
* @param type the type of the <code>Entity</code>
|
||||
* @param data the <code>Entity</code>'s data
|
||||
* @return the <code>Entity</code> requested or a new <code>Entity</code>
|
||||
* if not found
|
||||
*/
|
||||
public Entity defineEntity(String name, int type, char data[]) {
|
||||
Entity ent = entityHash.get(name);
|
||||
if (ent == null) {
|
||||
ent = new Entity(name, type, data);
|
||||
entityHash.put(name, ent);
|
||||
if (((type & GENERAL) != 0) && (data.length == 1)) {
|
||||
switch (type & ~GENERAL) {
|
||||
case CDATA:
|
||||
case SDATA:
|
||||
entityHash.put(Integer.valueOf(data[0]), ent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>Element</code> which matches the
|
||||
* specified parameters. If one doesn't exist, a new
|
||||
* one is created and returned.
|
||||
*
|
||||
* @param name the name of the <code>Element</code>
|
||||
* @param type the type of the <code>Element</code>
|
||||
* @param omitStart <code>true</code> if start should be omitted
|
||||
* @param omitEnd <code>true</code> if end should be omitted
|
||||
* @param content the <code>ContentModel</code>
|
||||
* @param atts the <code>AttributeList</code> specifying the
|
||||
* <code>Element</code>
|
||||
* @return the <code>Element</code> specified
|
||||
*/
|
||||
public Element defineElement(String name, int type,
|
||||
boolean omitStart, boolean omitEnd, ContentModel content,
|
||||
BitSet exclusions, BitSet inclusions, AttributeList atts) {
|
||||
Element e = getElement(name);
|
||||
e.type = type;
|
||||
e.oStart = omitStart;
|
||||
e.oEnd = omitEnd;
|
||||
e.content = content;
|
||||
e.exclusions = exclusions;
|
||||
e.inclusions = inclusions;
|
||||
e.atts = atts;
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines attributes for an {@code Element}.
|
||||
*
|
||||
* @param name the name of the <code>Element</code>
|
||||
* @param atts the <code>AttributeList</code> specifying the
|
||||
* <code>Element</code>
|
||||
*/
|
||||
public void defineAttributes(String name, AttributeList atts) {
|
||||
Element e = getElement(name);
|
||||
e.atts = atts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a character <code>Entity</code>.
|
||||
* @param name the entity's name
|
||||
* @return the new character <code>Entity</code>
|
||||
*/
|
||||
public Entity defEntity(String name, int type, int ch) {
|
||||
char data[] = {(char)ch};
|
||||
return defineEntity(name, type, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns an <code>Entity</code>.
|
||||
* @param name the entity's name
|
||||
* @return the new <code>Entity</code>
|
||||
*/
|
||||
protected Entity defEntity(String name, int type, String str) {
|
||||
int len = str.length();
|
||||
char data[] = new char[len];
|
||||
str.getChars(0, len, data, 0);
|
||||
return defineEntity(name, type, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns an <code>Element</code>.
|
||||
* @param name the element's name
|
||||
* @return the new <code>Element</code>
|
||||
*/
|
||||
protected Element defElement(String name, int type,
|
||||
boolean omitStart, boolean omitEnd, ContentModel content,
|
||||
String[] exclusions, String[] inclusions, AttributeList atts) {
|
||||
BitSet excl = null;
|
||||
if (exclusions != null && exclusions.length > 0) {
|
||||
excl = new BitSet();
|
||||
for (String str : exclusions) {
|
||||
if (str.length() > 0) {
|
||||
excl.set(getElement(str).getIndex());
|
||||
}
|
||||
}
|
||||
}
|
||||
BitSet incl = null;
|
||||
if (inclusions != null && inclusions.length > 0) {
|
||||
incl = new BitSet();
|
||||
for (String str : inclusions) {
|
||||
if (str.length() > 0) {
|
||||
incl.set(getElement(str).getIndex());
|
||||
}
|
||||
}
|
||||
}
|
||||
return defineElement(name, type, omitStart, omitEnd, content, excl, incl, atts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns an <code>AttributeList</code>.
|
||||
* @param name the attribute list's name
|
||||
* @return the new <code>AttributeList</code>
|
||||
*/
|
||||
protected AttributeList defAttributeList(String name, int type, int modifier, String value, String values, AttributeList atts) {
|
||||
Vector<String> vals = null;
|
||||
if (values != null) {
|
||||
vals = new Vector<String>();
|
||||
for (StringTokenizer s = new StringTokenizer(values, "|") ; s.hasMoreTokens() ;) {
|
||||
String str = s.nextToken();
|
||||
if (str.length() > 0) {
|
||||
vals.addElement(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new AttributeList(name, type, modifier, value, vals, atts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new content model.
|
||||
* @param type the type of the new content model
|
||||
* @return the new <code>ContentModel</code>
|
||||
*/
|
||||
protected ContentModel defContentModel(int type, Object obj, ContentModel next) {
|
||||
return new ContentModel(type, obj, next);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this DTD.
|
||||
* @return the string representation of this DTD
|
||||
*/
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* The hashtable key of DTDs in AppContext.
|
||||
*/
|
||||
private static final Object DTD_HASH_KEY = new Object();
|
||||
|
||||
public static void putDTDHash(String name, DTD dtd) {
|
||||
getDtdHash().put(name, dtd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a DTD with the specified <code>name</code>. If
|
||||
* a DTD with that name doesn't exist, one is created
|
||||
* and returned. Any uppercase characters in the name
|
||||
* are converted to lowercase.
|
||||
*
|
||||
* @param name the name of the DTD
|
||||
* @return the DTD which corresponds to <code>name</code>
|
||||
*/
|
||||
public static DTD getDTD(String name) throws IOException {
|
||||
name = name.toLowerCase();
|
||||
DTD dtd = getDtdHash().get(name);
|
||||
if (dtd == null)
|
||||
dtd = new DTD(name);
|
||||
|
||||
return dtd;
|
||||
}
|
||||
|
||||
private static Hashtable<String, DTD> getDtdHash() {
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
|
||||
Hashtable<String, DTD> result = (Hashtable<String, DTD>) appContext.get(DTD_HASH_KEY);
|
||||
|
||||
if (result == null) {
|
||||
result = new Hashtable<String, DTD>();
|
||||
|
||||
appContext.put(DTD_HASH_KEY, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recreates a DTD from an archived format.
|
||||
* @param in the <code>DataInputStream</code> to read from
|
||||
*/
|
||||
public void read(DataInputStream in) throws IOException {
|
||||
if (in.readInt() != FILE_VERSION) {
|
||||
}
|
||||
|
||||
//
|
||||
// Read the list of names
|
||||
//
|
||||
String[] names = new String[in.readShort()];
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
names[i] = in.readUTF();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Read the entities
|
||||
//
|
||||
int num = in.readShort();
|
||||
for (int i = 0; i < num; i++) {
|
||||
short nameId = in.readShort();
|
||||
int type = in.readByte();
|
||||
String name = in.readUTF();
|
||||
defEntity(names[nameId], type | GENERAL, name);
|
||||
}
|
||||
|
||||
// Read the elements
|
||||
//
|
||||
num = in.readShort();
|
||||
for (int i = 0; i < num; i++) {
|
||||
short nameId = in.readShort();
|
||||
int type = in.readByte();
|
||||
byte flags = in.readByte();
|
||||
ContentModel m = readContentModel(in, names);
|
||||
String[] exclusions = readNameArray(in, names);
|
||||
String[] inclusions = readNameArray(in, names);
|
||||
AttributeList atts = readAttributeList(in, names);
|
||||
defElement(names[nameId], type,
|
||||
((flags & 0x01) != 0), ((flags & 0x02) != 0),
|
||||
m, exclusions, inclusions, atts);
|
||||
}
|
||||
}
|
||||
|
||||
private ContentModel readContentModel(DataInputStream in, String[] names)
|
||||
throws IOException {
|
||||
byte flag = in.readByte();
|
||||
switch(flag) {
|
||||
case 0: // null
|
||||
return null;
|
||||
case 1: { // content_c
|
||||
int type = in.readByte();
|
||||
ContentModel m = readContentModel(in, names);
|
||||
ContentModel next = readContentModel(in, names);
|
||||
return defContentModel(type, m, next);
|
||||
}
|
||||
case 2: { // content_e
|
||||
int type = in.readByte();
|
||||
Element el = getElement(names[in.readShort()]);
|
||||
ContentModel next = readContentModel(in, names);
|
||||
return defContentModel(type, el, next);
|
||||
}
|
||||
default:
|
||||
throw new IOException("bad bdtd");
|
||||
}
|
||||
}
|
||||
|
||||
private String[] readNameArray(DataInputStream in, String[] names)
|
||||
throws IOException {
|
||||
int num = in.readShort();
|
||||
if (num == 0) {
|
||||
return null;
|
||||
}
|
||||
String[] result = new String[num];
|
||||
for (int i = 0; i < num; i++) {
|
||||
result[i] = names[in.readShort()];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private AttributeList readAttributeList(DataInputStream in, String[] names)
|
||||
throws IOException {
|
||||
AttributeList result = null;
|
||||
for (int num = in.readByte(); num > 0; --num) {
|
||||
short nameId = in.readShort();
|
||||
int type = in.readByte();
|
||||
int modifier = in.readByte();
|
||||
short valueId = in.readShort();
|
||||
String value = (valueId == -1) ? null : names[valueId];
|
||||
Vector<String> values = null;
|
||||
short numValues = in.readShort();
|
||||
if (numValues > 0) {
|
||||
values = new Vector<String>(numValues);
|
||||
for (int i = 0; i < numValues; i++) {
|
||||
values.addElement(names[in.readShort()]);
|
||||
}
|
||||
}
|
||||
result = new AttributeList(names[nameId], type, modifier, value,
|
||||
values, result);
|
||||
// We reverse the order of the linked list by doing this, but
|
||||
// that order isn't important.
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
82
jdkSrc/jdk8/javax/swing/text/html/parser/DTDConstants.java
Normal file
82
jdkSrc/jdk8/javax/swing/text/html/parser/DTDConstants.java
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 1999, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.text.html.parser;
|
||||
|
||||
/**
|
||||
* SGML constants used in a DTD. The names of the
|
||||
* constants correspond the the equivalent SGML constructs
|
||||
* as described in "The SGML Handbook" by Charles F. Goldfarb.
|
||||
*
|
||||
* @see DTD
|
||||
* @see Element
|
||||
* @author Arthur van Hoff
|
||||
*/
|
||||
public
|
||||
interface DTDConstants {
|
||||
// Attribute value types
|
||||
int CDATA = 1;
|
||||
int ENTITY = 2;
|
||||
int ENTITIES = 3;
|
||||
int ID = 4;
|
||||
int IDREF = 5;
|
||||
int IDREFS = 6;
|
||||
int NAME = 7;
|
||||
int NAMES = 8;
|
||||
int NMTOKEN = 9;
|
||||
int NMTOKENS = 10;
|
||||
int NOTATION = 11;
|
||||
int NUMBER = 12;
|
||||
int NUMBERS = 13;
|
||||
int NUTOKEN = 14;
|
||||
int NUTOKENS = 15;
|
||||
|
||||
// Content model types
|
||||
int RCDATA = 16;
|
||||
int EMPTY = 17;
|
||||
int MODEL = 18;
|
||||
int ANY = 19;
|
||||
|
||||
// Attribute value modifiers
|
||||
int FIXED = 1;
|
||||
int REQUIRED = 2;
|
||||
int CURRENT = 3;
|
||||
int CONREF = 4;
|
||||
int IMPLIED = 5;
|
||||
|
||||
// Entity types
|
||||
int PUBLIC = 10;
|
||||
int SDATA = 11;
|
||||
int PI = 12;
|
||||
int STARTTAG = 13;
|
||||
int ENDTAG = 14;
|
||||
int MS = 15;
|
||||
int MD = 16;
|
||||
int SYSTEM = 17;
|
||||
|
||||
int GENERAL = 1<<16;
|
||||
int DEFAULT = 1<<17;
|
||||
int PARAMETER = 1<<18;
|
||||
}
|
||||
281
jdkSrc/jdk8/javax/swing/text/html/parser/DocumentParser.java
Normal file
281
jdkSrc/jdk8/javax/swing/text/html/parser/DocumentParser.java
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.text.html.parser;
|
||||
|
||||
import javax.swing.text.SimpleAttributeSet;
|
||||
import javax.swing.text.html.HTMLEditorKit;
|
||||
import javax.swing.text.html.HTML;
|
||||
import javax.swing.text.ChangedCharSetException;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
|
||||
/**
|
||||
* A Parser for HTML Documents (actually, you can specify a DTD, but
|
||||
* you should really only use this class with the html dtd in swing).
|
||||
* Reads an InputStream of HTML and
|
||||
* invokes the appropriate methods in the ParserCallback class. This
|
||||
* is the default parser used by HTMLEditorKit to parse HTML url's.
|
||||
* <p>This will message the callback for all valid tags, as well as
|
||||
* tags that are implied but not explicitly specified. For example, the
|
||||
* html string (<p>blah) only has a p tag defined. The callback
|
||||
* will see the following methods:
|
||||
* <ol><li><i>handleStartTag(html, ...)</i></li>
|
||||
* <li><i>handleStartTag(head, ...)</i></li>
|
||||
* <li><i>handleEndTag(head)</i></li>
|
||||
* <li><i>handleStartTag(body, ...)</i></li>
|
||||
* <li><i>handleStartTag(p, ...)</i></li>
|
||||
* <li><i>handleText(...)</i></li>
|
||||
* <li><i>handleEndTag(p)</i></li>
|
||||
* <li><i>handleEndTag(body)</i></li>
|
||||
* <li><i>handleEndTag(html)</i></li>
|
||||
* </ol>
|
||||
* The items in <i>italic</i> are implied, that is, although they were not
|
||||
* explicitly specified, to be correct html they should have been present
|
||||
* (head isn't necessary, but it is still generated). For tags that
|
||||
* are implied, the AttributeSet argument will have a value of
|
||||
* <code>Boolean.TRUE</code> for the key
|
||||
* <code>HTMLEditorKit.ParserCallback.IMPLIED</code>.
|
||||
* <p>HTML.Attributes defines a type safe enumeration of html attributes.
|
||||
* If an attribute key of a tag is defined in HTML.Attribute, the
|
||||
* HTML.Attribute will be used as the key, otherwise a String will be used.
|
||||
* For example <p foo=bar class=neat> has two attributes. foo is
|
||||
* not defined in HTML.Attribute, where as class is, therefore the
|
||||
* AttributeSet will have two values in it, HTML.Attribute.CLASS with
|
||||
* a String value of 'neat' and the String key 'foo' with a String value of
|
||||
* 'bar'.
|
||||
* <p>The position argument will indicate the start of the tag, comment
|
||||
* or text. Similar to arrays, the first character in the stream has a
|
||||
* position of 0. For tags that are
|
||||
* implied the position will indicate
|
||||
* the location of the next encountered tag. In the first example,
|
||||
* the implied start body and html tags will have the same position as the
|
||||
* p tag, and the implied end p, html and body tags will all have the same
|
||||
* position.
|
||||
* <p>As html skips whitespace the position for text will be the position
|
||||
* of the first valid character, eg in the string '\n\n\nblah'
|
||||
* the text 'blah' will have a position of 3, the newlines are skipped.
|
||||
* <p>
|
||||
* For attributes that do not have a value, eg in the html
|
||||
* string <code><foo blah></code> the attribute <code>blah</code>
|
||||
* does not have a value, there are two possible values that will be
|
||||
* placed in the AttributeSet's value:
|
||||
* <ul>
|
||||
* <li>If the DTD does not contain an definition for the element, or the
|
||||
* definition does not have an explicit value then the value in the
|
||||
* AttributeSet will be <code>HTML.NULL_ATTRIBUTE_VALUE</code>.
|
||||
* <li>If the DTD contains an explicit value, as in:
|
||||
* <code><!ATTLIST OPTION selected (selected) #IMPLIED></code>
|
||||
* this value from the dtd (in this case selected) will be used.
|
||||
* </ul>
|
||||
* <p>
|
||||
* Once the stream has been parsed, the callback is notified of the most
|
||||
* likely end of line string. The end of line string will be one of
|
||||
* \n, \r or \r\n, which ever is encountered the most in parsing the
|
||||
* stream.
|
||||
*
|
||||
* @author Sunita Mani
|
||||
*/
|
||||
public class DocumentParser extends javax.swing.text.html.parser.Parser {
|
||||
|
||||
private int inbody;
|
||||
private int intitle;
|
||||
private int inhead;
|
||||
private int instyle;
|
||||
private int inscript;
|
||||
private boolean seentitle;
|
||||
private HTMLEditorKit.ParserCallback callback = null;
|
||||
private boolean ignoreCharSet = false;
|
||||
private static final boolean debugFlag = false;
|
||||
|
||||
public DocumentParser(DTD dtd) {
|
||||
super(dtd);
|
||||
}
|
||||
|
||||
public void parse(Reader in, HTMLEditorKit.ParserCallback callback, boolean ignoreCharSet) throws IOException {
|
||||
this.ignoreCharSet = ignoreCharSet;
|
||||
this.callback = callback;
|
||||
parse(in);
|
||||
// end of line
|
||||
callback.handleEndOfLineString(getEndOfLineString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Start Tag.
|
||||
*/
|
||||
protected void handleStartTag(TagElement tag) {
|
||||
|
||||
Element elem = tag.getElement();
|
||||
if (elem == dtd.body) {
|
||||
inbody++;
|
||||
} else if (elem == dtd.html) {
|
||||
} else if (elem == dtd.head) {
|
||||
inhead++;
|
||||
} else if (elem == dtd.title) {
|
||||
intitle++;
|
||||
} else if (elem == dtd.style) {
|
||||
instyle++;
|
||||
} else if (elem == dtd.script) {
|
||||
inscript++;
|
||||
}
|
||||
if (debugFlag) {
|
||||
if (tag.fictional()) {
|
||||
debug("Start Tag: " + tag.getHTMLTag() + " pos: " + getCurrentPos());
|
||||
} else {
|
||||
debug("Start Tag: " + tag.getHTMLTag() + " attributes: " +
|
||||
getAttributes() + " pos: " + getCurrentPos());
|
||||
}
|
||||
}
|
||||
if (tag.fictional()) {
|
||||
SimpleAttributeSet attrs = new SimpleAttributeSet();
|
||||
attrs.addAttribute(HTMLEditorKit.ParserCallback.IMPLIED,
|
||||
Boolean.TRUE);
|
||||
callback.handleStartTag(tag.getHTMLTag(), attrs,
|
||||
getBlockStartPosition());
|
||||
} else {
|
||||
callback.handleStartTag(tag.getHTMLTag(), getAttributes(),
|
||||
getBlockStartPosition());
|
||||
flushAttributes();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void handleComment(char text[]) {
|
||||
if (debugFlag) {
|
||||
debug("comment: ->" + new String(text) + "<-"
|
||||
+ " pos: " + getCurrentPos());
|
||||
}
|
||||
callback.handleComment(text, getBlockStartPosition());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Empty Tag.
|
||||
*/
|
||||
protected void handleEmptyTag(TagElement tag) throws ChangedCharSetException {
|
||||
|
||||
Element elem = tag.getElement();
|
||||
if (elem == dtd.meta && !ignoreCharSet) {
|
||||
SimpleAttributeSet atts = getAttributes();
|
||||
if (atts != null) {
|
||||
String content = (String)atts.getAttribute(HTML.Attribute.CONTENT);
|
||||
if (content != null) {
|
||||
if ("content-type".equalsIgnoreCase((String)atts.getAttribute(HTML.Attribute.HTTPEQUIV))) {
|
||||
if (!content.equalsIgnoreCase("text/html") &&
|
||||
!content.equalsIgnoreCase("text/plain")) {
|
||||
throw new ChangedCharSetException(content, false);
|
||||
}
|
||||
} else if ("charset" .equalsIgnoreCase((String)atts.getAttribute(HTML.Attribute.HTTPEQUIV))) {
|
||||
throw new ChangedCharSetException(content, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inbody != 0 || elem == dtd.meta || elem == dtd.base || elem == dtd.isindex || elem == dtd.style || elem == dtd.link) {
|
||||
if (debugFlag) {
|
||||
if (tag.fictional()) {
|
||||
debug("Empty Tag: " + tag.getHTMLTag() + " pos: " + getCurrentPos());
|
||||
} else {
|
||||
debug("Empty Tag: " + tag.getHTMLTag() + " attributes: "
|
||||
+ getAttributes() + " pos: " + getCurrentPos());
|
||||
}
|
||||
}
|
||||
if (tag.fictional()) {
|
||||
SimpleAttributeSet attrs = new SimpleAttributeSet();
|
||||
attrs.addAttribute(HTMLEditorKit.ParserCallback.IMPLIED,
|
||||
Boolean.TRUE);
|
||||
callback.handleSimpleTag(tag.getHTMLTag(), attrs,
|
||||
getBlockStartPosition());
|
||||
} else {
|
||||
callback.handleSimpleTag(tag.getHTMLTag(), getAttributes(),
|
||||
getBlockStartPosition());
|
||||
flushAttributes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle End Tag.
|
||||
*/
|
||||
protected void handleEndTag(TagElement tag) {
|
||||
Element elem = tag.getElement();
|
||||
if (elem == dtd.body) {
|
||||
inbody--;
|
||||
} else if (elem == dtd.title) {
|
||||
intitle--;
|
||||
seentitle = true;
|
||||
} else if (elem == dtd.head) {
|
||||
inhead--;
|
||||
} else if (elem == dtd.style) {
|
||||
instyle--;
|
||||
} else if (elem == dtd.script) {
|
||||
inscript--;
|
||||
}
|
||||
if (debugFlag) {
|
||||
debug("End Tag: " + tag.getHTMLTag() + " pos: " + getCurrentPos());
|
||||
}
|
||||
callback.handleEndTag(tag.getHTMLTag(), getBlockStartPosition());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Text.
|
||||
*/
|
||||
protected void handleText(char data[]) {
|
||||
if (data != null) {
|
||||
if (inscript != 0) {
|
||||
callback.handleComment(data, getBlockStartPosition());
|
||||
return;
|
||||
}
|
||||
if (inbody != 0 || ((instyle != 0) ||
|
||||
((intitle != 0) && !seentitle))) {
|
||||
if (debugFlag) {
|
||||
debug("text: ->" + new String(data) + "<-" + " pos: " + getCurrentPos());
|
||||
}
|
||||
callback.handleText(data, getBlockStartPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Error handling.
|
||||
*/
|
||||
protected void handleError(int ln, String errorMsg) {
|
||||
if (debugFlag) {
|
||||
debug("Error: ->" + errorMsg + "<-" + " pos: " + getCurrentPos());
|
||||
}
|
||||
/* PENDING: need to improve the error string. */
|
||||
callback.handleError(errorMsg, getCurrentPos());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* debug messages
|
||||
*/
|
||||
private void debug(String msg) {
|
||||
System.out.println(msg);
|
||||
}
|
||||
}
|
||||
185
jdkSrc/jdk8/javax/swing/text/html/parser/Element.java
Normal file
185
jdkSrc/jdk8/javax/swing/text/html/parser/Element.java
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.text.html.parser;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.BitSet;
|
||||
import java.io.*;
|
||||
import sun.awt.AppContext;
|
||||
|
||||
/**
|
||||
* An element as described in a DTD using the ELEMENT construct.
|
||||
* This is essential the description of a tag. It describes the
|
||||
* type, content model, attributes, attribute types etc. It is used
|
||||
* to correctly parse a document by the Parser.
|
||||
*
|
||||
* @see DTD
|
||||
* @see AttributeList
|
||||
* @author Arthur van Hoff
|
||||
*/
|
||||
public final
|
||||
class Element implements DTDConstants, Serializable {
|
||||
public int index;
|
||||
public String name;
|
||||
public boolean oStart;
|
||||
public boolean oEnd;
|
||||
public BitSet inclusions;
|
||||
public BitSet exclusions;
|
||||
public int type = ANY;
|
||||
public ContentModel content;
|
||||
public AttributeList atts;
|
||||
|
||||
/**
|
||||
* A field to store user data. Mostly used to store
|
||||
* style sheets.
|
||||
*/
|
||||
public Object data;
|
||||
|
||||
Element() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new element.
|
||||
*/
|
||||
Element(String name, int index) {
|
||||
this.name = name;
|
||||
this.index = index;
|
||||
if (index > getMaxIndex()) {
|
||||
AppContext.getAppContext().put(MAX_INDEX_KEY, index);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Object MAX_INDEX_KEY = new Object();
|
||||
|
||||
static int getMaxIndex() {
|
||||
Integer value = (Integer) AppContext.getAppContext().get(MAX_INDEX_KEY);
|
||||
return (value != null)
|
||||
? value.intValue()
|
||||
: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the element.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the start tag can be omitted.
|
||||
*/
|
||||
public boolean omitStart() {
|
||||
return oStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the end tag can be omitted.
|
||||
*/
|
||||
public boolean omitEnd() {
|
||||
return oEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get type.
|
||||
*/
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content model
|
||||
*/
|
||||
public ContentModel getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attributes.
|
||||
*/
|
||||
public AttributeList getAttributes() {
|
||||
return atts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get index.
|
||||
*/
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if empty
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return type == EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to a string.
|
||||
*/
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an attribute by name.
|
||||
*/
|
||||
public AttributeList getAttribute(String name) {
|
||||
for (AttributeList a = atts ; a != null ; a = a.next) {
|
||||
if (a.name.equals(name)) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an attribute by value.
|
||||
*/
|
||||
public AttributeList getAttributeByValue(String name) {
|
||||
for (AttributeList a = atts ; a != null ; a = a.next) {
|
||||
if ((a.values != null) && a.values.contains(name)) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
static Hashtable<String, Integer> contentTypes = new Hashtable<String, Integer>();
|
||||
|
||||
static {
|
||||
contentTypes.put("CDATA", Integer.valueOf(CDATA));
|
||||
contentTypes.put("RCDATA", Integer.valueOf(RCDATA));
|
||||
contentTypes.put("EMPTY", Integer.valueOf(EMPTY));
|
||||
contentTypes.put("ANY", Integer.valueOf(ANY));
|
||||
}
|
||||
|
||||
public static int name2type(String nm) {
|
||||
Integer val = contentTypes.get(nm);
|
||||
return (val != null) ? val.intValue() : 0;
|
||||
}
|
||||
}
|
||||
139
jdkSrc/jdk8/javax/swing/text/html/parser/Entity.java
Normal file
139
jdkSrc/jdk8/javax/swing/text/html/parser/Entity.java
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.text.html.parser;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.CharArrayReader;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* An entity is described in a DTD using the ENTITY construct.
|
||||
* It defines the type and value of the the entity.
|
||||
*
|
||||
* @see DTD
|
||||
* @author Arthur van Hoff
|
||||
*/
|
||||
public final
|
||||
class Entity implements DTDConstants {
|
||||
public String name;
|
||||
public int type;
|
||||
public char data[];
|
||||
|
||||
/**
|
||||
* Creates an entity.
|
||||
* @param name the name of the entity
|
||||
* @param type the type of the entity
|
||||
* @param data the char array of data
|
||||
*/
|
||||
public Entity(String name, int type, char data[]) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the entity.
|
||||
* @return the name of the entity, as a <code>String</code>
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the entity.
|
||||
* @return the type of the entity
|
||||
*/
|
||||
public int getType() {
|
||||
return type & 0xFFFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if it is a parameter entity.
|
||||
* @return <code>true</code> if it is a parameter entity
|
||||
*/
|
||||
public boolean isParameter() {
|
||||
return (type & PARAMETER) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if it is a general entity.
|
||||
* @return <code>true</code> if it is a general entity
|
||||
*/
|
||||
public boolean isGeneral() {
|
||||
return (type & GENERAL) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>data</code>.
|
||||
* @return the <code>data</code>
|
||||
*/
|
||||
public char getData()[] {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data as a <code>String</code>.
|
||||
* @return the data as a <code>String</code>
|
||||
*/
|
||||
public String getString() {
|
||||
return new String(data, 0, data.length);
|
||||
}
|
||||
|
||||
|
||||
static Hashtable<String, Integer> entityTypes = new Hashtable<String, Integer>();
|
||||
|
||||
static {
|
||||
entityTypes.put("PUBLIC", Integer.valueOf(PUBLIC));
|
||||
entityTypes.put("CDATA", Integer.valueOf(CDATA));
|
||||
entityTypes.put("SDATA", Integer.valueOf(SDATA));
|
||||
entityTypes.put("PI", Integer.valueOf(PI));
|
||||
entityTypes.put("STARTTAG", Integer.valueOf(STARTTAG));
|
||||
entityTypes.put("ENDTAG", Integer.valueOf(ENDTAG));
|
||||
entityTypes.put("MS", Integer.valueOf(MS));
|
||||
entityTypes.put("MD", Integer.valueOf(MD));
|
||||
entityTypes.put("SYSTEM", Integer.valueOf(SYSTEM));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts <code>nm</code> string to the corresponding
|
||||
* entity type. If the string does not have a corresponding
|
||||
* entity type, returns the type corresponding to "CDATA".
|
||||
* Valid entity types are: "PUBLIC", "CDATA", "SDATA", "PI",
|
||||
* "STARTTAG", "ENDTAG", "MS", "MD", "SYSTEM".
|
||||
*
|
||||
* @param nm the string to be converted
|
||||
* @return the corresponding entity type, or the type corresponding
|
||||
* to "CDATA", if none exists
|
||||
*/
|
||||
public static int name2type(String nm) {
|
||||
Integer i = entityTypes.get(nm);
|
||||
return (i == null) ? CDATA : i.intValue();
|
||||
}
|
||||
}
|
||||
2353
jdkSrc/jdk8/javax/swing/text/html/parser/Parser.java
Normal file
2353
jdkSrc/jdk8/javax/swing/text/html/parser/Parser.java
Normal file
File diff suppressed because it is too large
Load Diff
129
jdkSrc/jdk8/javax/swing/text/html/parser/ParserDelegator.java
Normal file
129
jdkSrc/jdk8/javax/swing/text/html/parser/ParserDelegator.java
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package javax.swing.text.html.parser;
|
||||
|
||||
import sun.awt.AppContext;
|
||||
|
||||
import javax.swing.text.html.HTMLEditorKit;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.Serializable;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* Responsible for starting up a new DocumentParser
|
||||
* each time its parse method is invoked. Stores a
|
||||
* reference to the dtd.
|
||||
*
|
||||
* @author Sunita Mani
|
||||
*/
|
||||
|
||||
public class ParserDelegator extends HTMLEditorKit.Parser implements Serializable {
|
||||
|
||||
private static final Object DTD_KEY = new Object();
|
||||
|
||||
protected static void setDefaultDTD() {
|
||||
getDefaultDTD();
|
||||
}
|
||||
|
||||
private static synchronized DTD getDefaultDTD() {
|
||||
AppContext appContext = AppContext.getAppContext();
|
||||
|
||||
DTD dtd = (DTD) appContext.get(DTD_KEY);
|
||||
|
||||
if (dtd == null) {
|
||||
DTD _dtd = null;
|
||||
// (PENDING) Hate having to hard code!
|
||||
String nm = "html32";
|
||||
try {
|
||||
_dtd = DTD.getDTD(nm);
|
||||
} catch (IOException e) {
|
||||
// (PENDING) UGLY!
|
||||
System.out.println("Throw an exception: could not get default dtd: " + nm);
|
||||
}
|
||||
dtd = createDTD(_dtd, nm);
|
||||
|
||||
appContext.put(DTD_KEY, dtd);
|
||||
}
|
||||
|
||||
return dtd;
|
||||
}
|
||||
|
||||
protected static DTD createDTD(DTD dtd, String name) {
|
||||
|
||||
InputStream in = null;
|
||||
boolean debug = true;
|
||||
try {
|
||||
String path = name + ".bdtd";
|
||||
in = getResourceAsStream(path);
|
||||
if (in != null) {
|
||||
dtd.read(new DataInputStream(new BufferedInputStream(in)));
|
||||
dtd.putDTDHash(name, dtd);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
return dtd;
|
||||
}
|
||||
|
||||
|
||||
public ParserDelegator() {
|
||||
setDefaultDTD();
|
||||
}
|
||||
|
||||
public void parse(Reader r, HTMLEditorKit.ParserCallback cb, boolean ignoreCharSet) throws IOException {
|
||||
new DocumentParser(getDefaultDTD()).parse(r, cb, ignoreCharSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a resource relative to the ParserDelegator classfile.
|
||||
* If this is called on 1.2 the loading will occur under the
|
||||
* protection of a doPrivileged call to allow the ParserDelegator
|
||||
* to function when used in an applet.
|
||||
*
|
||||
* @param name the name of the resource, relative to the
|
||||
* ParserDelegator class.
|
||||
* @returns a stream representing the resource
|
||||
*/
|
||||
static InputStream getResourceAsStream(final String name) {
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<InputStream>() {
|
||||
public InputStream run() {
|
||||
return ParserDelegator.class.getResourceAsStream(name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream s)
|
||||
throws ClassNotFoundException, IOException {
|
||||
s.defaultReadObject();
|
||||
setDefaultDTD();
|
||||
}
|
||||
}
|
||||
74
jdkSrc/jdk8/javax/swing/text/html/parser/TagElement.java
Normal file
74
jdkSrc/jdk8/javax/swing/text/html/parser/TagElement.java
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.text.html.parser;
|
||||
|
||||
import javax.swing.text.html.HTML;
|
||||
/**
|
||||
* A generic HTML TagElement class. The methods define how white
|
||||
* space is interpreted around the tag.
|
||||
*
|
||||
* @author Sunita Mani
|
||||
*/
|
||||
|
||||
public class TagElement {
|
||||
|
||||
Element elem;
|
||||
HTML.Tag htmlTag;
|
||||
boolean insertedByErrorRecovery;
|
||||
|
||||
public TagElement ( Element elem ) {
|
||||
this(elem, false);
|
||||
}
|
||||
|
||||
public TagElement (Element elem, boolean fictional) {
|
||||
this.elem = elem;
|
||||
htmlTag = HTML.getTag(elem.getName());
|
||||
if (htmlTag == null) {
|
||||
htmlTag = new HTML.UnknownTag(elem.getName());
|
||||
}
|
||||
insertedByErrorRecovery = fictional;
|
||||
}
|
||||
|
||||
public boolean breaksFlow() {
|
||||
return htmlTag.breaksFlow();
|
||||
}
|
||||
|
||||
public boolean isPreformatted() {
|
||||
return htmlTag.isPreformatted();
|
||||
}
|
||||
|
||||
public Element getElement() {
|
||||
return elem;
|
||||
}
|
||||
|
||||
public HTML.Tag getHTMLTag() {
|
||||
return htmlTag;
|
||||
}
|
||||
|
||||
public boolean fictional() {
|
||||
return insertedByErrorRecovery;
|
||||
}
|
||||
}
|
||||
204
jdkSrc/jdk8/javax/swing/text/html/parser/TagStack.java
Normal file
204
jdkSrc/jdk8/javax/swing/text/html/parser/TagStack.java
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing.text.html.parser;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.util.Vector;
|
||||
import java.io.*;
|
||||
|
||||
|
||||
/**
|
||||
* A stack of tags. Used while parsing an HTML document.
|
||||
* It, together with the ContentModelStates, defines the
|
||||
* complete state of the parser while reading a document.
|
||||
* When a start tag is encountered an element is pushed onto
|
||||
* the stack, when an end tag is enountered an element is popped
|
||||
* of the stack.
|
||||
*
|
||||
* @see Parser
|
||||
* @see DTD
|
||||
* @see ContentModelState
|
||||
* @author Arthur van Hoff
|
||||
*/
|
||||
final
|
||||
class TagStack implements DTDConstants {
|
||||
TagElement tag;
|
||||
Element elem;
|
||||
ContentModelState state;
|
||||
TagStack next;
|
||||
BitSet inclusions;
|
||||
BitSet exclusions;
|
||||
boolean net;
|
||||
boolean pre;
|
||||
|
||||
/**
|
||||
* Construct a stack element.
|
||||
*/
|
||||
TagStack(TagElement tag, TagStack next) {
|
||||
this.tag = tag;
|
||||
this.elem = tag.getElement();
|
||||
this.next = next;
|
||||
|
||||
Element elem = tag.getElement();
|
||||
if (elem.getContent() != null) {
|
||||
this.state = new ContentModelState(elem.getContent());
|
||||
}
|
||||
|
||||
if (next != null) {
|
||||
inclusions = next.inclusions;
|
||||
exclusions = next.exclusions;
|
||||
pre = next.pre;
|
||||
}
|
||||
if (tag.isPreformatted()) {
|
||||
pre = true;
|
||||
}
|
||||
|
||||
if (elem.inclusions != null) {
|
||||
if (inclusions != null) {
|
||||
inclusions = (BitSet)inclusions.clone();
|
||||
inclusions.or(elem.inclusions);
|
||||
} else {
|
||||
inclusions = elem.inclusions;
|
||||
}
|
||||
}
|
||||
if (elem.exclusions != null) {
|
||||
if (exclusions != null) {
|
||||
exclusions = (BitSet)exclusions.clone();
|
||||
exclusions.or(elem.exclusions);
|
||||
} else {
|
||||
exclusions = elem.exclusions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the element that must come next in the
|
||||
* input stream.
|
||||
*/
|
||||
public Element first() {
|
||||
return (state != null) ? state.first() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ContentModel that must be satisfied by
|
||||
* what comes next in the input stream.
|
||||
*/
|
||||
public ContentModel contentModel() {
|
||||
if (state == null) {
|
||||
return null;
|
||||
} else {
|
||||
return state.getModel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the element that is contained at
|
||||
* the index specified by the parameter is part of
|
||||
* the exclusions specified in the DTD for the element
|
||||
* currently on the TagStack.
|
||||
*/
|
||||
boolean excluded(int elemIndex) {
|
||||
return (exclusions != null) && exclusions.get(elem.getIndex());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Advance the state by reducing the given element.
|
||||
* Returns false if the element is not legal and the
|
||||
* state is not advanced.
|
||||
*/
|
||||
boolean advance(Element elem) {
|
||||
if ((exclusions != null) && exclusions.get(elem.getIndex())) {
|
||||
return false;
|
||||
}
|
||||
if (state != null) {
|
||||
ContentModelState newState = state.advance(elem);
|
||||
if (newState != null) {
|
||||
state = newState;
|
||||
return true;
|
||||
}
|
||||
} else if (this.elem.getType() == ANY) {
|
||||
return true;
|
||||
}
|
||||
return (inclusions != null) && inclusions.get(elem.getIndex());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the current state can be terminated.
|
||||
*/
|
||||
boolean terminate() {
|
||||
return (state == null) || state.terminate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to a string.
|
||||
*/
|
||||
public String toString() {
|
||||
return (next == null) ?
|
||||
"<" + tag.getElement().getName() + ">" :
|
||||
next + " <" + tag.getElement().getName() + ">";
|
||||
}
|
||||
}
|
||||
|
||||
class NPrintWriter extends PrintWriter {
|
||||
|
||||
private int numLines = 5;
|
||||
private int numPrinted = 0;
|
||||
|
||||
public NPrintWriter (int numberOfLines) {
|
||||
super(System.out);
|
||||
numLines = numberOfLines;
|
||||
}
|
||||
|
||||
public void println(char[] array) {
|
||||
if (numPrinted >= numLines) {
|
||||
return;
|
||||
}
|
||||
|
||||
char[] partialArray = null;
|
||||
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
if (array[i] == '\n') {
|
||||
numPrinted++;
|
||||
}
|
||||
|
||||
if (numPrinted == numLines) {
|
||||
System.arraycopy(array, 0, partialArray, 0, i);
|
||||
}
|
||||
}
|
||||
|
||||
if (partialArray != null) {
|
||||
super.print(partialArray);
|
||||
}
|
||||
|
||||
if (numPrinted == numLines) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.println(array);
|
||||
numPrinted++;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user