diff options
Diffstat (limited to 'libjava/classpath/javax/swing/text/html')
-rw-r--r-- | libjava/classpath/javax/swing/text/html/BlockView.java | 301 | ||||
-rw-r--r-- | libjava/classpath/javax/swing/text/html/CSS.java | 3 | ||||
-rw-r--r-- | libjava/classpath/javax/swing/text/html/CSSParser.java | 568 | ||||
-rw-r--r-- | libjava/classpath/javax/swing/text/html/HTMLDocument.java | 1337 | ||||
-rw-r--r-- | libjava/classpath/javax/swing/text/html/HTMLEditorKit.java | 945 | ||||
-rw-r--r-- | libjava/classpath/javax/swing/text/html/StyleSheet.java | 937 | ||||
-rw-r--r-- | libjava/classpath/javax/swing/text/html/default.css | 378 |
7 files changed, 4438 insertions, 31 deletions
diff --git a/libjava/classpath/javax/swing/text/html/BlockView.java b/libjava/classpath/javax/swing/text/html/BlockView.java new file mode 100644 index 00000000000..6274e7b1756 --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/BlockView.java @@ -0,0 +1,301 @@ +/* BlockView.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html; + +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.Shape; + +import javax.swing.SizeRequirements; +import javax.swing.event.DocumentEvent; +import javax.swing.text.AttributeSet; +import javax.swing.text.BoxView; +import javax.swing.text.Element; +import javax.swing.text.View; +import javax.swing.text.ViewFactory; + +/** + * @author Lillian Angel <langel@redhat.com> + */ +public class BlockView extends BoxView +{ + + /** + * 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); + } + + /** + * Creates the parent view for this. It is called before + * any other methods, if the parent view is working properly. + * Implemented to forward to the superclass and call + * setPropertiesFromAttributes to set the paragraph + * properties. + * + * @param parent - the new parent, or null if the view + * is being removed from a parent it was added to. + */ + public void setParent(View parent) + { + super.setParent(parent); + + if (parent != null) + setPropertiesFromAttributes(); + } + + /** + * Calculates the requirements along the major axis. + * This is implemented to call the superclass and then + * adjust it if the CSS width or height attribute is specified + * and applicable. + * + * @param axis - the axis to check the requirements for. + * @param r - the SizeRequirements. If null, one is created. + * @return the new SizeRequirements object. + */ + protected SizeRequirements calculateMajorAxisRequirements(int axis, + SizeRequirements r) + { + SizeRequirements sr = super.calculateMajorAxisRequirements(axis, r); + // FIXME: adjust it if the CSS width or height attribute is specified + // and applicable + return sr; + } + + /** + * Calculates the requirements along the minor axis. + * This is implemented to call the superclass and then + * adjust it if the CSS width or height attribute is specified + * and applicable. + * + * @param axis - the axis to check the requirements for. + * @param r - the SizeRequirements. If null, one is created. + * @return the new SizeRequirements object. + */ + protected SizeRequirements calculateMinorAxisRequirements(int axis, + SizeRequirements r) + { + SizeRequirements sr = super.calculateMinorAxisRequirements(axis, r); + // FIXME: adjust it if the CSS width or height attribute is specified + // and applicable. + return sr; + } + + /** + * Lays out the box along the minor axis (the axis that is + * perpendicular to the axis that it represents). The results + * of the layout are placed in the given arrays which are + * the allocations to the children along the minor axis. + * + * @param targetSpan - the total span given to the view, also + * used to layout the children. + * @param axis - the minor axis + * @param offsets - the offsets from the origin of the view for + * all the child views. This is a return value and is filled in by this + * function. + * @param spans - the span of each child view. This is a return value and is + * filled in by this function. + */ + protected void layoutMinorAxis(int targetSpan, int axis, + int[] offsets, int[] spans) + { + // FIXME: Not implemented. + super.layoutMinorAxis(targetSpan, axis, offsets, spans); + } + + /** + * Paints using the given graphics configuration and shape. + * This delegates to the css box painter to paint the + * border and background prior to the interior. + * + * @param g - Graphics configuration + * @param a - the Shape to render into. + */ + public void paint(Graphics g, Shape a) + { + Rectangle rect = (Rectangle) a; + // FIXME: not fully implemented + getStyleSheet().getBoxPainter(getAttributes()).paint(g, rect.x, rect.y, + rect.width, + rect.height, this); + super.paint(g, a); + } + + /** + * Fetches the attributes to use when painting. + * + * @return the attributes of this model. + */ + public AttributeSet getAttributes() + { + return getStyleSheet().getViewAttributes(this); + } + + /** + * Gets the resize weight. + * + * @param axis - the axis to get the resize weight for. + * @return the resize weight. + * @throws IllegalArgumentException - for an invalid axis + */ + public int getResizeWeight(int axis) throws IllegalArgumentException + { + // Can't resize the Y_AXIS + if (axis == Y_AXIS) + return 0; + if (axis == X_AXIS) + return 1; + throw new IllegalArgumentException("Invalid Axis"); + } + + /** + * Gets the alignment. + * + * @param axis - the axis to get the alignment for. + * @return the alignment. + */ + public float getAlignment(int axis) + { + if (axis == X_AXIS) + return 0.0F; + if (axis == Y_AXIS) + { + if (getViewCount() == 0) + return 0.0F; + float prefHeight = getPreferredSpan(Y_AXIS); + float firstRowHeight = getView(0).getPreferredSpan(Y_AXIS); + return (firstRowHeight / 2.F) / prefHeight; + } + throw new IllegalArgumentException("Invalid Axis"); + } + + /** + * Gives notification from the document that attributes were + * changed in a location that this view is responsible for. + * + * @param ev - the change information + * @param a - the current shape of the view + * @param f - the factory to use to rebuild if the view has children. + */ + public void changedUpdate(DocumentEvent ev, + Shape a, ViewFactory f) + { + super.changedUpdate(ev, a, f); + + // If more elements were added, then need to set the properties for them + int currPos = ev.getOffset(); + if (currPos <= getStartOffset() && (currPos + ev.getLength()) >= getEndOffset()) + setPropertiesFromAttributes(); + } + + /** + * Determines the preferred span along the axis. + * + * @param axis - the view to get the preferred span for. + * @return the span the view would like to be painted into >=0/ + * The view is usually told to paint into the span that is returned, + * although the parent may choose to resize or break the view. + * @throws IllegalArgumentException - for an invalid axis + */ + public float getPreferredSpan(int axis) throws IllegalArgumentException + { + if (axis == X_AXIS || axis == Y_AXIS) + return super.getPreferredSpan(axis); + throw new IllegalArgumentException("Invalid Axis"); + } + + /** + * Determines the minimum span along the axis. + * + * @param axis - the axis to get the minimum span for. + * @return the span the view would like to be painted into >=0/ + * The view is usually told to paint into the span that is returned, + * although the parent may choose to resize or break the view. + * @throws IllegalArgumentException - for an invalid axis + */ + public float getMinimumSpan(int axis) throws IllegalArgumentException + { + if (axis == X_AXIS || axis == Y_AXIS) + return super.getMinimumSpan(axis); + throw new IllegalArgumentException("Invalid Axis"); + } + + /** + * Determines the maximum span along the axis. + * + * @param axis - the axis to get the maximum span for. + * @return the span the view would like to be painted into >=0/ + * The view is usually told to paint into the span that is returned, + * although the parent may choose to resize or break the view. + * @throws IllegalArgumentException - for an invalid axis + */ + public float getMaximumSpan(int axis) throws IllegalArgumentException + { + if (axis == X_AXIS || axis == Y_AXIS) + return super.getMaximumSpan(axis); + throw new IllegalArgumentException("Invalid Axis"); + } + + /** + * Updates any cached values that come from attributes. + */ + protected void setPropertiesFromAttributes() + { + // FIXME: Not implemented (need to use StyleSheet). + } + + /** + * Gets the default style sheet. + * + * @return the style sheet + */ + protected StyleSheet getStyleSheet() + { + StyleSheet styleSheet = new StyleSheet(); + styleSheet.importStyleSheet(getClass().getResource(HTMLEditorKit.DEFAULT_CSS)); + return styleSheet; + } +} diff --git a/libjava/classpath/javax/swing/text/html/CSS.java b/libjava/classpath/javax/swing/text/html/CSS.java index 029ad26f8a9..c248e758ec2 100644 --- a/libjava/classpath/javax/swing/text/html/CSS.java +++ b/libjava/classpath/javax/swing/text/html/CSS.java @@ -37,6 +37,7 @@ exception statement from your version. */ package javax.swing.text.html; +import java.io.Serializable; import java.util.HashMap; /** @@ -46,7 +47,7 @@ import java.util.HashMap; * * @author Roman Kennke (kennke@aicas.com) */ -public class CSS +public class CSS implements Serializable { /** * Returns an array of all CSS attributes. diff --git a/libjava/classpath/javax/swing/text/html/CSSParser.java b/libjava/classpath/javax/swing/text/html/CSSParser.java new file mode 100644 index 00000000000..0bf76eb809f --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/CSSParser.java @@ -0,0 +1,568 @@ +/* CSSParser.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html; + +import java.io.*; + +/** + * Parses a CSS document. This works by way of a delegate that implements the + * CSSParserCallback interface. The delegate is notified of the following + * events: + * - Import statement: handleImport + * - Selectors handleSelector. This is invoked for each string. For example if + * the Reader contained p, bar , a {}, the delegate would be notified 4 times, + * for 'p,' 'bar' ',' and 'a'. + * - When a rule starts, startRule + * - Properties in the rule via the handleProperty. This + * is invoked one per property/value key, eg font size: foo;, would cause the + * delegate to be notified once with a value of 'font size'. + * - Values in the rule via the handleValue, this is notified for the total value. + * - When a rule ends, endRule + * + * @author Lillian Angel (langel@redhat.com) + */ +class CSSParser +{ + + /** + * Receives all information about the CSS document structure while parsing it. + * The methods are invoked by parser. + */ + static interface CSSParserCallback + { + /** + * Handles the import statment in the document. + * + * @param imp - the import string + */ + public abstract void handleImport(String imp); + + /** + * Called when the start of a rule is encountered. + */ + public abstract void startRule(); + + /** + * Called when the end of a rule is encountered. + */ + public abstract void endRule(); + + /** + * Handles the selector of a rule. + * + * @param selector - the selector in the rule + */ + public abstract void handleSelector(String selector); + + /** + * Handles the properties in the document. + * + * @param property - the property in the document. + */ + public abstract void handleProperty(String property); + + /** + * Handles the values in the document. + * + * @param value - the value to handle. + */ + public abstract void handleValue(String value); + + } + + /** + * The identifier of the rule. + */ + private static final int IDENTIFIER = 1; + + /** + * The open bracket. + */ + private static final int BRACKET_OPEN = 2; + + /** + * The close bracket. + */ + private static final int BRACKET_CLOSE = 3; + + /** + * The open brace. + */ + private static final int BRACE_OPEN = 4; + + /** + * The close brace. + */ + private static final int BRACE_CLOSE = 5; + + /** + * The open parentheses. + */ + private static final int PAREN_OPEN = 6; + + /** + * The close parentheses. + */ + private static final int PAREN_CLOSE = 7; + + /** + * The end of the document. + */ + private static final int END = -1; + + /** + * The character mapping in the document. + */ + // FIXME: What is this used for? + private static final char[] charMapping = null; + + /** + * Set to true if one character has been read ahead. + */ + private boolean didPushChar; + + /** + * The read ahead character. + */ + private int pushedChar; + + /** + * 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; + + /** + * The call back used to parse. + */ + private CSSParser.CSSParserCallback callback; + + /** + * nextToken() inserts the string here. + */ + private char[] tokenBuffer; + + /** + * Current number of chars in tokenBufferLength. + */ + private int tokenBufferLength; + + /** + * Set to true if any whitespace is read. + */ + private boolean readWS; + + /** + * Constructor + */ + CSSParser() + { + unitBuffer = new StringBuffer(); + tokenBuffer = new char[10]; + } + + /** + * Appends a character to the token buffer. + * + * @param c - the character to append + */ + private void append(char c) + { + if (tokenBuffer.length >= tokenBufferLength) + { + char[] temp = new char[tokenBufferLength * 2]; + if (tokenBuffer != null) + System.arraycopy(tokenBuffer, 0, temp, 0, tokenBufferLength); + + temp[tokenBufferLength] = c; + tokenBuffer = temp; + } + else + tokenBuffer[tokenBufferLength] = c; + tokenBufferLength++; + } + + /** + * Fetches the next token. + * + * @param c - the character to fetch. + * @return the location + * @throws IOException - any i/o error encountered while reading + */ + private int nextToken(char c) throws IOException + { + readWS = false; + int next = readWS(); + + switch (next) + { + case '\"': + if (tokenBufferLength > 0) + tokenBufferLength--; + return IDENTIFIER; + case '\'': + if (tokenBufferLength > 0) + tokenBufferLength--; + return IDENTIFIER; + case '(': + return PAREN_OPEN; + case ')': + return PAREN_CLOSE; + case '{': + return BRACE_OPEN; + case '}': + return BRACE_CLOSE; + case '[': + return BRACKET_OPEN; + case ']': + return BRACKET_CLOSE; + case -1: + return END; + default: + pushChar(next); + getIdentifier(c); + return IDENTIFIER; + } + } + + /** + * Reads a character from the stream. + * + * @return the number of characters read or -1 if end of stream is reached. + * @throws IOException - any i/o encountered while reading + */ + private int readChar() throws IOException + { + if (didPushChar) + { + didPushChar = false; + return pushedChar; + } + return reader.read(); + } + + /** + * Parses the the contents of the reader using the + * callback. + * + * @param reader - the reader to read from + * @param callback - the callback instance + * @param parsingDeclaration - true if parsing a declaration + * @throws IOException - any i/o error from the reader + */ + void parse(Reader reader, CSSParser.CSSParserCallback callback, + boolean parsingDeclaration) + throws IOException + { + this.reader = reader; + this.callback = callback; + + try + { + if (!parsingDeclaration) + while(getNextStatement()); + else + parseDeclarationBlock(); + } + catch (IOException ioe) + { + // Nothing to do here. + } + } + + /** + * Skips any white space, returning the character after the white space. + * + * @return the character after the whitespace + * @throws IOException - any i/o error from the reader + */ + private int readWS() throws IOException + { + int next = readChar(); + while (Character.isWhitespace((char) next)) + { + readWS = true; + int tempNext = readChar(); + if (tempNext == END) + return next; + next = tempNext; + } + + // Its all whitespace + return END; + } + + /** + * Gets the next statement, returning false if the end is reached. + * A statement is either an At-rule, or a ruleset. + * + * @return false if the end is reached + * @throws IOException - any i/o error from the reader + */ + private boolean getNextStatement() throws IOException + { + int c = nextToken((char) 0); + switch (c) + { + case PAREN_OPEN: + case BRACE_OPEN: + case BRACKET_OPEN: + parseTillClosed(c); + break; + case BRACKET_CLOSE: + case BRACE_CLOSE: + case PAREN_CLOSE: + throw new IOException("Not a proper statement."); + case IDENTIFIER: + if (tokenBuffer[0] == ('@')) + parseAtRule(); + else + parseRuleSet(); + break; + case END: + return false; + } + return true; + } + + /** + * Parses an @ rule, stopping at a matching brace pair, or ;. + * + * @throws IOException - any i/o error from the reader + */ + private void parseAtRule() throws IOException + { + // An At-Rule begins with the "@" character followed immediately by a keyword. + // Following the keyword separated by a space is an At-rule statement appropriate + // to the At-keyword used. If the At-Rule is a simple declarative statement + // (charset, import, fontdef), it is terminated by a semi-colon (";".) + // If the At-Rule is a conditional or informative statement (media, page, font-face), + // it is followed by optional arguments and then a style declaration block inside matching + // curly braces ("{", "}".) At-Rules are sometimes nestable, depending on the context. + // If any part of an At-Rule is not understood, it should be ignored. + + // FIXME: Not Implemented + // call handleimport + } + + /** + * Parses the next rule set, which is a selector followed by a declaration + * block. + * + * @throws IOException - any i/o error from the reader + */ + private void parseRuleSet() throws IOException + { + // call parseDeclarationBlock + // call parse selectors + // call parse identifiers + // call startrule/endrule + // FIXME: Not Implemented + } + + /** + * Parses a set of selectors, returning false if the end of the stream is + * reached. + * + * @return false if the end of stream is reached + * @throws IOException - any i/o error from the reader + */ + private boolean parseSelectors() throws IOException + { + // FIXME: Not Implemented + // call handleselector + return false; + } + + /** + * Parses a declaration block. Which a number of declarations followed by a + * })]. + * + * @throws IOException - any i/o error from the reader + */ + private void parseDeclarationBlock() throws IOException + { + // call parseDeclaration + // FIXME: Not Implemented + } + + /** + * Parses a single declaration, which is an identifier a : and another identifier. + * This returns the last token seen. + * + * @returns the last token + * @throws IOException - any i/o error from the reader + */ + private int parseDeclaration() throws IOException + { + // call handleValue + // FIXME: Not Implemented + return 0; + } + + /** + * Parses identifiers until c is encountered, returning the ending token, + * which will be IDENTIFIER if c is found. + * + * @param c - the stop character + * @param wantsBlocks - true if blocks are wanted + * @return the ending token + * @throws IOException - any i/o error from the reader + */ + private int parseIdentifiers(char c, boolean wantsBlocks) throws IOException + { + // FIXME: Not implemented + // call handleproperty? + return 0; + } + + /** + * Parses till a matching block close is encountered. This is only appropriate + * to be called at the top level (no nesting). + * + * @param i - FIXME + * @throws IOException - any i/o error from the reader + */ + private void parseTillClosed(int i) throws IOException + { + // FIXME: Not Implemented + } + + /** + * Gets an identifier, returning true if the length of the string is greater + * than 0, stopping when c, whitespace, or one of {}()[] is hit. + * + * @param c - the stop character + * @return returns true if the length of the string > 0 + * @throws IOException - any i/o error from the reader + */ + private boolean getIdentifier(char c) throws IOException + { + // FIXME: Not Implemented + return false; + } + + /** + * Reads till c is encountered, escaping characters as necessary. + * + * @param c - the stop character + * @throws IOException - any i/o error from the reader + */ + private void readTill(char c) throws IOException + { + // FIXME: Not Implemented + } + + /** + * Parses a comment block. + * + * @throws IOException - any i/o error from the reader + */ + private void readComment() throws IOException + { + // Should ignore comments. Read until end of comment. + // FIXME: Not implemented + } + + /** + * Called when a block start is encountered ({[. + * + * @param start of block + */ + private void startBlock(int start) + { + // FIXME: Not Implemented + } + + /** + * Called when an end block is encountered )]} + * + * @param end of block + */ + private void endBlock(int end) + { + // FIXME: Not Implemented + } + + /** + * Checks if currently in a block. + * + * @return true if currently in a block. + */ + private boolean inBlock() + { + // FIXME: Not Implemented + return false; + } + + /** + * Supports one character look ahead, this will throw if called twice in a row. + * + * @param c - the character to push. + * @throws IOException - if called twice in a row + */ + private void pushChar(int c) throws IOException + { + if (didPushChar) + throw new IOException("pushChar called twice."); + didPushChar = true; + pushedChar = c; + } +} + +
\ No newline at end of file diff --git a/libjava/classpath/javax/swing/text/html/HTMLDocument.java b/libjava/classpath/javax/swing/text/html/HTMLDocument.java index d048a04e614..5b2452b32f6 100644 --- a/libjava/classpath/javax/swing/text/html/HTMLDocument.java +++ b/libjava/classpath/javax/swing/text/html/HTMLDocument.java @@ -40,17 +40,32 @@ package javax.swing.text.html; import java.net.URL; +import java.io.IOException; + +import java.util.HashMap; +import java.util.Stack; +import java.util.Vector; + +import javax.swing.event.DocumentEvent; +import javax.swing.event.UndoableEditEvent; import javax.swing.text.AbstractDocument; import javax.swing.text.AttributeSet; +import javax.swing.text.BadLocationException; import javax.swing.text.DefaultStyledDocument; import javax.swing.text.Element; import javax.swing.text.ElementIterator; +import javax.swing.text.GapContent; +import javax.swing.text.MutableAttributeSet; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.StyleConstants; import javax.swing.text.html.HTML.Tag; /** - * TODO: This class is not yet completetely implemented. - * + * TODO: Add more comments here + * * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + * @author Anthony Balkissoon (abalkiss@redhat.com) + * @author Lillian Angel (langel@redhat.com) */ public class HTMLDocument extends DefaultStyledDocument { @@ -60,6 +75,195 @@ public class HTMLDocument extends DefaultStyledDocument public static final String AdditionalComments = "AdditionalComments"; URL baseURL = null; boolean preservesUnknownTags = true; + int tokenThreshold = Integer.MAX_VALUE; + HTMLEditorKit.Parser parser; + StyleSheet styleSheet; + AbstractDocument.Content content; + + /** + * Constructs an HTML document using the default buffer size and a default + * StyleSheet. + */ + public HTMLDocument() + { + this(null); + } + + /** + * Constructs an HTML document with the default content storage + * implementation and the specified style/attribute storage mechanism. + * + * @param styles - the style sheet + */ + public HTMLDocument(StyleSheet styles) + { + this(new GapContent(BUFFER_SIZE_DEFAULT), styles); + } + + /** + * Constructs an HTML document with the given content storage implementation + * and the given style/attribute storage mechanism. + * + * @param c - the document's content + * @param styles - the style sheet + */ + public HTMLDocument(AbstractDocument.Content c, StyleSheet styles) + { + this.content = c; + if (styles == null) + { + styles = new StyleSheet(); + styles.importStyleSheet(getClass().getResource(HTMLEditorKit. + DEFAULT_CSS)); + } + this.styleSheet = styles; + } + + /** + * Gets the style sheet with the document display rules (CSS) that were specified + * in the HTML document. + * + * @return - the style sheet + */ + public StyleSheet getStyleSheet() + { + return styleSheet; + } + + /** + * Replaces the contents of the document with the given element specifications. + * This is called before insert if the loading is done in bursts. This is the + * only method called if loading the document entirely in one burst. + * + * @param data - the date that replaces the content of the document + */ + protected void create(DefaultStyledDocument.ElementSpec[] data) + { + // FIXME: Not implemented + System.out.println("create not implemented"); + super.create(data); + } + + /** + * This method creates a root element for the new document. + * + * @return the new default root + */ + protected AbstractDocument.AbstractElement createDefaultRoot() + { + // FIXME: Not implemented + System.out.println("createDefaultRoot not implemented"); + return super.createDefaultRoot(); + } + + /** + * This method returns an HTMLDocument.RunElement object attached to + * parent representing a run of text from p0 to p1. The run has + * attributes described by a. + * + * @param parent - the parent element + * @param a - the attributes for the element + * @param p0 - the beginning of the range >= 0 + * @param p1 - the end of the range >= p0 + * @return the new element + */ + protected Element createLeafElement(Element parent, AttributeSet a, int p0, + int p1) + { + // FIXME: Not implemented + System.out.println("createLeafElement not implemented"); + return super.createLeafElement(parent, a, p0, p1); + } + + /** This method returns an HTMLDocument.BlockElement object representing the + * attribute set a and attached to parent. + * + * @param parent - the parent element + * @param a - the attributes for the element + * @return the new element + */ + protected Element createBranchElement(Element parent, AttributeSet a) + { + // FIXME: Not implemented + System.out.println("createBranchElement not implemented"); + return super.createBranchElement(parent, a); + } + + /** + * Inserts new elements in bulk. This is how elements get created in the + * document. The parsing determines what structure is needed and creates the + * specification as a set of tokens that describe the edit while leaving the + * document free of a write-lock. This method can then be called in bursts by + * the reader to acquire a write-lock for a shorter duration (i.e. while the + * document is actually being altered). + * + * @param offset - the starting offset + * @param data - the element data + * @throws BadLocationException - if the given position does not + * represent a valid location in the associated document. + */ + protected void insert(int offset, DefaultStyledDocument.ElementSpec[] data) + throws BadLocationException + { + super.insert(offset, data); + } + + /** + * Updates document structure as a result of text insertion. This will happen + * within a write lock. This implementation simply parses the inserted content + * for line breaks and builds up a set of instructions for the element buffer. + * + * @param chng - a description of the document change + * @param attr - the attributes + */ + protected void insertUpdate(AbstractDocument.DefaultDocumentEvent chng, + AttributeSet attr) + { + // FIXME: Not implemented + System.out.println("insertUpdate not implemented"); + super.insertUpdate(chng, attr); + } + + /** + * Returns the parser used by this HTMLDocument to insert HTML. + * + * @return the parser used by this HTMLDocument to insert HTML. + */ + public HTMLEditorKit.Parser getParser() + { + return parser; + } + + /** + * Sets the parser used by this HTMLDocument to insert HTML. + * + * @param p the parser to use + */ + public void setParser (HTMLEditorKit.Parser p) + { + parser = p; + } + /** + * Sets the number of tokens to buffer before trying to display the + * Document. + * + * @param n the number of tokens to buffer + */ + public void setTokenThreshold (int n) + { + tokenThreshold = n; + } + + /** + * Returns the number of tokens that are buffered before the document + * is rendered. + * + * @return the number of tokens buffered + */ + public int getTokenThreshold () + { + return tokenThreshold; + } /** * Returns the location against which to resolve relative URLs. @@ -79,7 +283,7 @@ public class HTMLDocument extends DefaultStyledDocument public void setBase(URL u) { baseURL = u; - //TODO: also set the base of the StyleSheet + styleSheet.setBase(u); } /** @@ -259,10 +463,1133 @@ public class HTMLDocument extends DefaultStyledDocument return null; } + /** + * Gets the name of the element. + * + * @return the name of the element if it exists, null otherwise. + */ public String getName() { - //FIXME: this is supposed to do something different from the super class - return super.getName(); + return (String) getAttribute(StyleConstants.NameAttribute); + } + } + + /** + * RunElement represents a section of text that has a set of + * HTML character level attributes assigned to it. + */ + public class RunElement extends AbstractDocument.LeafElement + { + + /** + * Constructs an element that has no children. It represents content + * within the document. + * + * @param parent - parent of this + * @param a - elements attributes + * @param start - the start offset >= 0 + * @param end - the end offset + */ + public RunElement(Element parent, AttributeSet a, int start, int end) + { + super(parent, a, start, end); + } + + /** + * Gets the name of the element. + * + * @return the name of the element if it exists, null otherwise. + */ + public String getName() + { + return (String) getAttribute(StyleConstants.NameAttribute); + } + + /** + * Gets the resolving parent. HTML attributes do not inherit at the + * model level, so this method returns null. + * + * @return null + */ + public AttributeSet getResolveParent() + { + return null; + } + } + + /** + * A reader to load an HTMLDocument with HTML structure. + * + * @author Anthony Balkissoon abalkiss at redhat dot com + */ + public class HTMLReader extends HTMLEditorKit.ParserCallback + { + /** Holds the current character attribute set **/ + protected MutableAttributeSet charAttr = new SimpleAttributeSet(); + + protected Vector parseBuffer = new Vector(); + + /** A stack for character attribute sets **/ + Stack charAttrStack = new Stack(); + + /** A mapping between HTML.Tag objects and the actions that handle them **/ + HashMap tagToAction; + + /** Tells us whether we've received the '</html>' tag yet **/ + boolean endHTMLEncountered = false; + + /** Variables related to the constructor with explicit insertTag **/ + int popDepth, pushDepth, offset; + HTML.Tag insertTag; + boolean insertTagEncountered = false; + + /** A temporary variable that helps with the printing out of debug information **/ + boolean debug = false; + + void print (String line) + { + if (debug) + System.out.println (line); + } + + public class TagAction + { + /** + * This method is called when a start tag is seen for one of the types + * of tags associated with this Action. By default this does nothing. + */ + public void start(HTML.Tag t, MutableAttributeSet a) + { + // Nothing to do here. + } + + /** + * Called when an end tag is seen for one of the types of tags associated + * with this Action. By default does nothing. + */ + public void end(HTML.Tag t) + { + // Nothing to do here. + } + } + + public class BlockAction extends TagAction + { + /** + * This method is called when a start tag is seen for one of the types + * of tags associated with this Action. + */ + public void start(HTML.Tag t, MutableAttributeSet a) + { + // Tell the parse buffer to open a new block for this tag. + blockOpen(t, a); + } + + /** + * Called when an end tag is seen for one of the types of tags associated + * with this Action. + */ + public void end(HTML.Tag t) + { + // Tell the parse buffer to close this block. + blockClose(t); + } + } + + public class CharacterAction extends TagAction + { + /** + * This method is called when a start tag is seen for one of the types + * of tags associated with this Action. + */ + public void start(HTML.Tag t, MutableAttributeSet a) + { + // Put the old attribute set on the stack. + pushCharacterStyle(); + + // And create the new one by adding the attributes in <code>a</code>. + if (a != null) + charAttr.addAttribute(t, a.copyAttributes()); + } + + /** + * Called when an end tag is seen for one of the types of tags associated + * with this Action. + */ + public void end(HTML.Tag t) + { + popCharacterStyle(); + } + } + + public class FormAction extends SpecialAction + { + /** + * This method is called when a start tag is seen for one of the types + * of tags associated with this Action. + */ + public void start(HTML.Tag t, MutableAttributeSet a) + { + // FIXME: Implement. + print ("FormAction.start not implemented"); + } + + /** + * Called when an end tag is seen for one of the types of tags associated + * with this Action. + */ + public void end(HTML.Tag t) + { + // FIXME: Implement. + print ("FormAction.end not implemented"); + } + } + + public class HiddenAction extends TagAction + { + /** + * This method is called when a start tag is seen for one of the types + * of tags associated with this Action. + */ + public void start(HTML.Tag t, MutableAttributeSet a) + { + // FIXME: Implement. + print ("HiddenAction.start not implemented"); + } + + /** + * Called when an end tag is seen for one of the types of tags associated + * with this Action. + */ + public void end(HTML.Tag t) + { + // FIXME: Implement. + print ("HiddenAction.end not implemented"); + } + } + + public class IsindexAction extends TagAction + { + /** + * This method is called when a start tag is seen for one of the types + * of tags associated with this Action. + */ + public void start(HTML.Tag t, MutableAttributeSet a) + { + // FIXME: Implement. + print ("IsindexAction.start not implemented"); + } + + /** + * Called when an end tag is seen for one of the types of tags associated + * with this Action. + */ + public void end(HTML.Tag t) + { + // FIXME: Implement. + print ("IsindexAction.end not implemented"); + } + } + + public class ParagraphAction extends BlockAction + { + /** + * This method is called when a start tag is seen for one of the types + * of tags associated with this Action. + */ + public void start(HTML.Tag t, MutableAttributeSet a) + { + // FIXME: Implement. + print ("ParagraphAction.start not implemented"); + } + + /** + * Called when an end tag is seen for one of the types of tags associated + * with this Action. + */ + public void end(HTML.Tag t) + { + // FIXME: Implement. + print ("ParagraphAction.end not implemented"); + } + } + + public class PreAction extends BlockAction + { + /** + * This method is called when a start tag is seen for one of the types + * of tags associated with this Action. + */ + public void start(HTML.Tag t, MutableAttributeSet a) + { + // FIXME: Implement. + print ("PreAction.start not implemented"); + } + + /** + * Called when an end tag is seen for one of the types of tags associated + * with this Action. + */ + public void end(HTML.Tag t) + { + // FIXME: Implement. + print ("PreAction.end not implemented"); + } + } + + public class SpecialAction extends TagAction + { + /** + * This method is called when a start tag is seen for one of the types + * of tags associated with this Action. + */ + public void start(HTML.Tag t, MutableAttributeSet a) + { + // FIXME: Implement. + print ("SpecialAction.start not implemented"); + } + + /** + * Called when an end tag is seen for one of the types of tags associated + * with this Action. + */ + public void end(HTML.Tag t) + { + // FIXME: Implement. + print ("SpecialAction.end not implemented"); + } + } + + class AreaAction extends TagAction + { + /** + * This method is called when a start tag is seen for one of the types + * of tags associated with this Action. + */ + public void start(HTML.Tag t, MutableAttributeSet a) + { + // FIXME: Implement. + print ("AreaAction.start not implemented"); + } + + /** + * Called when an end tag is seen for one of the types of tags associated + * with this Action. + */ + public void end(HTML.Tag t) + { + // FIXME: Implement. + print ("AreaAction.end not implemented"); + } + } + + class BaseAction extends TagAction + { + /** + * This method is called when a start tag is seen for one of the types + * of tags associated with this Action. + */ + public void start(HTML.Tag t, MutableAttributeSet a) + { + // FIXME: Implement. + print ("BaseAction.start not implemented"); + } + + /** + * Called when an end tag is seen for one of the types of tags associated + * with this Action. + */ + public void end(HTML.Tag t) + { + // FIXME: Implement. + print ("BaseAction.end not implemented"); + } + } + + class HeadAction extends BlockAction + { + /** + * This method is called when a start tag is seen for one of the types + * of tags associated with this Action. + */ + public void start(HTML.Tag t, MutableAttributeSet a) + { + // FIXME: Implement. + print ("HeadAction.start not implemented: "+t); + super.start(t, a); + } + + /** + * Called when an end tag is seen for one of the types of tags associated + * with this Action. + */ + public void end(HTML.Tag t) + { + // FIXME: Implement. + print ("HeadAction.end not implemented: "+t); + super.end(t); + } + } + + class LinkAction extends TagAction + { + /** + * This method is called when a start tag is seen for one of the types + * of tags associated with this Action. + */ + public void start(HTML.Tag t, MutableAttributeSet a) + { + // FIXME: Implement. + print ("LinkAction.start not implemented"); + } + + /** + * Called when an end tag is seen for one of the types of tags associated + * with this Action. + */ + public void end(HTML.Tag t) + { + // FIXME: Implement. + print ("LinkAction.end not implemented"); + } + } + + class MapAction extends TagAction + { + /** + * This method is called when a start tag is seen for one of the types + * of tags associated with this Action. + */ + public void start(HTML.Tag t, MutableAttributeSet a) + { + // FIXME: Implement. + print ("MapAction.start not implemented"); + } + + /** + * Called when an end tag is seen for one of the types of tags associated + * with this Action. + */ + public void end(HTML.Tag t) + { + // FIXME: Implement. + print ("MapAction.end not implemented"); + } + } + + class MetaAction extends TagAction + { + /** + * This method is called when a start tag is seen for one of the types + * of tags associated with this Action. + */ + public void start(HTML.Tag t, MutableAttributeSet a) + { + // FIXME: Implement. + print ("MetaAction.start not implemented"); + } + + /** + * Called when an end tag is seen for one of the types of tags associated + * with this Action. + */ + public void end(HTML.Tag t) + { + // FIXME: Implement. + print ("MetaAction.end not implemented"); + } + } + + class StyleAction extends TagAction + { + /** + * This method is called when a start tag is seen for one of the types + * of tags associated with this Action. + */ + public void start(HTML.Tag t, MutableAttributeSet a) + { + // FIXME: Implement. + print ("StyleAction.start not implemented"); + } + + /** + * Called when an end tag is seen for one of the types of tags associated + * with this Action. + */ + public void end(HTML.Tag t) + { + // FIXME: Implement. + print ("StyleAction.end not implemented"); + } + } + + class TitleAction extends TagAction + { + /** + * This method is called when a start tag is seen for one of the types + * of tags associated with this Action. + */ + public void start(HTML.Tag t, MutableAttributeSet a) + { + // FIXME: Implement. + print ("TitleAction.start not implemented"); + } + + /** + * Called when an end tag is seen for one of the types of tags associated + * with this Action. + */ + public void end(HTML.Tag t) + { + // FIXME: Implement. + print ("TitleAction.end not implemented"); + } + } + + public HTMLReader(int offset) + { + this (offset, 0, 0, null); + } + + public HTMLReader(int offset, int popDepth, int pushDepth, + HTML.Tag insertTag) + { + print ("HTMLReader created with pop: "+popDepth + + " push: "+pushDepth + " offset: "+offset + + " tag: "+insertTag); + this.insertTag = insertTag; + this.offset = offset; + this.popDepth = popDepth; + this.pushDepth = pushDepth; + initTags(); + } + + void initTags() + { + tagToAction = new HashMap(72); + CharacterAction characterAction = new CharacterAction(); + HiddenAction hiddenAction = new HiddenAction(); + AreaAction areaAction = new AreaAction(); + BaseAction baseAction = new BaseAction(); + BlockAction blockAction = new BlockAction(); + SpecialAction specialAction = new SpecialAction(); + ParagraphAction paragraphAction = new ParagraphAction(); + HeadAction headAction = new HeadAction(); + FormAction formAction = new FormAction(); + IsindexAction isindexAction = new IsindexAction(); + LinkAction linkAction = new LinkAction(); + MapAction mapAction = new MapAction(); + PreAction preAction = new PreAction(); + MetaAction metaAction = new MetaAction(); + StyleAction styleAction = new StyleAction(); + TitleAction titleAction = new TitleAction(); + + + tagToAction.put(HTML.Tag.A, characterAction); + tagToAction.put(HTML.Tag.ADDRESS, characterAction); + tagToAction.put(HTML.Tag.APPLET, hiddenAction); + tagToAction.put(HTML.Tag.AREA, areaAction); + tagToAction.put(HTML.Tag.B, characterAction); + tagToAction.put(HTML.Tag.BASE, baseAction); + tagToAction.put(HTML.Tag.BASEFONT, characterAction); + tagToAction.put(HTML.Tag.BIG, characterAction); + tagToAction.put(HTML.Tag.BLOCKQUOTE, blockAction); + tagToAction.put(HTML.Tag.BODY, blockAction); + tagToAction.put(HTML.Tag.BR, specialAction); + tagToAction.put(HTML.Tag.CAPTION, blockAction); + tagToAction.put(HTML.Tag.CENTER, blockAction); + tagToAction.put(HTML.Tag.CITE, characterAction); + tagToAction.put(HTML.Tag.CODE, characterAction); + tagToAction.put(HTML.Tag.DD, blockAction); + tagToAction.put(HTML.Tag.DFN, characterAction); + tagToAction.put(HTML.Tag.DIR, blockAction); + tagToAction.put(HTML.Tag.DIV, blockAction); + tagToAction.put(HTML.Tag.DL, blockAction); + tagToAction.put(HTML.Tag.DT, paragraphAction); + tagToAction.put(HTML.Tag.EM, characterAction); + tagToAction.put(HTML.Tag.FONT, characterAction); + tagToAction.put(HTML.Tag.FORM, blockAction); + tagToAction.put(HTML.Tag.FRAME, specialAction); + tagToAction.put(HTML.Tag.FRAMESET, blockAction); + tagToAction.put(HTML.Tag.H1, paragraphAction); + tagToAction.put(HTML.Tag.H2, paragraphAction); + tagToAction.put(HTML.Tag.H3, paragraphAction); + tagToAction.put(HTML.Tag.H4, paragraphAction); + tagToAction.put(HTML.Tag.H5, paragraphAction); + tagToAction.put(HTML.Tag.H6, paragraphAction); + tagToAction.put(HTML.Tag.HEAD, headAction); + tagToAction.put(HTML.Tag.HR, specialAction); + tagToAction.put(HTML.Tag.HTML, blockAction); + tagToAction.put(HTML.Tag.I, characterAction); + tagToAction.put(HTML.Tag.IMG, specialAction); + tagToAction.put(HTML.Tag.INPUT, formAction); + tagToAction.put(HTML.Tag.ISINDEX, isindexAction); + tagToAction.put(HTML.Tag.KBD, characterAction); + tagToAction.put(HTML.Tag.LI, blockAction); + tagToAction.put(HTML.Tag.LINK, linkAction); + tagToAction.put(HTML.Tag.MAP, mapAction); + tagToAction.put(HTML.Tag.MENU, blockAction); + tagToAction.put(HTML.Tag.META, metaAction); + tagToAction.put(HTML.Tag.NOFRAMES, blockAction); + tagToAction.put(HTML.Tag.OBJECT, specialAction); + tagToAction.put(HTML.Tag.OL, blockAction); + tagToAction.put(HTML.Tag.OPTION, formAction); + tagToAction.put(HTML.Tag.P, paragraphAction); + tagToAction.put(HTML.Tag.PARAM, hiddenAction); + tagToAction.put(HTML.Tag.PRE, preAction); + tagToAction.put(HTML.Tag.SAMP, characterAction); + tagToAction.put(HTML.Tag.SCRIPT, hiddenAction); + tagToAction.put(HTML.Tag.SELECT, formAction); + tagToAction.put(HTML.Tag.SMALL, characterAction); + tagToAction.put(HTML.Tag.STRIKE, characterAction); + tagToAction.put(HTML.Tag.S, characterAction); + tagToAction.put(HTML.Tag.STRONG, characterAction); + tagToAction.put(HTML.Tag.STYLE, styleAction); + tagToAction.put(HTML.Tag.SUB, characterAction); + tagToAction.put(HTML.Tag.SUP, characterAction); + tagToAction.put(HTML.Tag.TABLE, blockAction); + tagToAction.put(HTML.Tag.TD, blockAction); + tagToAction.put(HTML.Tag.TEXTAREA, formAction); + tagToAction.put(HTML.Tag.TH, blockAction); + tagToAction.put(HTML.Tag.TITLE, titleAction); + tagToAction.put(HTML.Tag.TR, blockAction); + tagToAction.put(HTML.Tag.TT, characterAction); + tagToAction.put(HTML.Tag.U, characterAction); + tagToAction.put(HTML.Tag.UL, blockAction); + tagToAction.put(HTML.Tag.VAR, characterAction); + } + + /** + * Pushes the current character style onto the stack. + * + */ + protected void pushCharacterStyle() + { + charAttrStack.push(charAttr); + } + + /** + * Pops a character style off of the stack and uses it as the + * current character style. + * + */ + protected void popCharacterStyle() + { + if (!charAttrStack.isEmpty()) + charAttr = (MutableAttributeSet) charAttrStack.pop(); + } + + /** + * Registers a given tag with a given Action. All of the well-known tags + * are registered by default, but this method can change their behaviour + * or add support for custom or currently unsupported tags. + * + * @param t the Tag to register + * @param a the Action for the Tag + */ + protected void registerTag(HTML.Tag t, HTMLDocument.HTMLReader.TagAction a) + { + tagToAction.put (t, a); + } + + /** + * This is the last method called on the HTMLReader, allowing any pending + * changes to be flushed to the HTMLDocument. + */ + public void flush() throws BadLocationException + { + DefaultStyledDocument.ElementSpec[] elements; + elements = new DefaultStyledDocument.ElementSpec[parseBuffer.size()]; + parseBuffer.copyInto(elements); + parseBuffer.removeAllElements(); + insert(offset, elements); + offset += HTMLDocument.this.getLength() - offset; + } + + /** + * This method is called by the parser to indicate a block of + * text was encountered. Should insert the text appropriately. + * + * @param data the text that was inserted + * @param pos the position at which the text was inserted + */ + public void handleText(char[] data, int pos) + { + if (data != null && data.length > 0) + addContent(data, 0, data.length); + } + + /** + * This method is called by the parser and should route the call to + * the proper handler for the tag. + * + * @param t the HTML.Tag + * @param a the attribute set + * @param pos the position at which the tag was encountered + */ + public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) + { + // Don't call the Action if we've already seen </html>. + if (endHTMLEncountered) + return; + + TagAction action = (TagAction) tagToAction.get(t); + if (action != null) + action.start(t, a); + } + + /** + * This method called by parser to handle a comment block. + * + * @param data the comment + * @param pos the position at which the comment was encountered + */ + public void handleComment(char[] data, int pos) + { + // Don't call the Action if we've already seen </html>. + if (endHTMLEncountered) + return; + + TagAction action = (TagAction) tagToAction.get(HTML.Tag.COMMENT); + if (action != null) + { + action.start(HTML.Tag.COMMENT, new SimpleAttributeSet()); + action.end (HTML.Tag.COMMENT); + } + } + + /** + * This method is called by the parser and should route the call to + * the proper handler for the tag. + * + * @param t the HTML.Tag + * @param pos the position at which the tag was encountered + */ + public void handleEndTag(HTML.Tag t, int pos) + { + // Don't call the Action if we've already seen </html>. + if (endHTMLEncountered) + return; + + // If this is the </html> tag we need to stop calling the Actions + if (t == HTML.Tag.HTML) + endHTMLEncountered = true; + + TagAction action = (TagAction) tagToAction.get(t); + if (action != null) + action.end(t); + } + + /** + * This is a callback from the parser that should be routed to the + * appropriate handler for the tag. + * + * @param t the HTML.Tag that was encountered + * @param a the attribute set + * @param pos the position at which the tag was encountered + */ + public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos) + { + // Don't call the Action if we've already seen </html>. + if (endHTMLEncountered) + return; + + TagAction action = (TagAction) tagToAction.get (t); + if (action != null) + { + action.start(t, a); + action.end(t); + } + } + + /** + * This is invoked after the stream has been parsed but before it has been + * flushed. + * + * @param eol one of \n, \r, or \r\n, whichever was encountered the most in + * parsing the stream + * @since 1.3 + */ + public void handleEndOfLineString(String eol) + { + // FIXME: Implement. + print ("HTMLReader.handleEndOfLineString not implemented yet"); + } + + /** + * Adds the given text to the textarea document. Called only when we are + * within a textarea. + * + * @param data the text to add to the textarea + */ + protected void textAreaContent(char[] data) + { + // FIXME: Implement. + print ("HTMLReader.textAreaContent not implemented yet"); + } + + /** + * Adds the given text that was encountered in a <PRE> element. + * + * @param data the text + */ + protected void preContent(char[] data) + { + // FIXME: Implement + print ("HTMLReader.preContent not implemented yet"); + } + + /** + * Instructs the parse buffer to create a block element with the given + * attributes. + * + * @param t the tag that requires opening a new block + * @param attr the attribute set for the new block + */ + protected void blockOpen(HTML.Tag t, MutableAttributeSet attr) + { + printBuffer(); + DefaultStyledDocument.ElementSpec element; + element = new DefaultStyledDocument.ElementSpec(attr.copyAttributes(), + DefaultStyledDocument.ElementSpec.StartTagType); + parseBuffer.addElement(element); + printBuffer(); + } + + /** + * Instructs the parse buffer to close the block element associated with + * the given HTML.Tag + * + * @param t the HTML.Tag that is closing its block + */ + protected void blockClose(HTML.Tag t) + { + printBuffer(); + DefaultStyledDocument.ElementSpec element; + element = new DefaultStyledDocument.ElementSpec(null, + DefaultStyledDocument.ElementSpec.EndTagType); + parseBuffer.addElement(element); + printBuffer(); } + + /** + * Adds text to the appropriate context using the current character + * attribute set. + * + * @param data the text to add + * @param offs the offset at which to add it + * @param length the length of the text to add + */ + protected void addContent(char[] data, int offs, int length) + { + addContent(data, offs, length, true); + } + + /** + * Adds text to the appropriate context using the current character + * attribute set, and possibly generating an IMPLIED Tag if necessary. + * + * @param data the text to add + * @param offs the offset at which to add it + * @param length the length of the text to add + * @param generateImpliedPIfNecessary whether or not we should generate + * an HTML.Tag.IMPLIED tag if necessary + */ + protected void addContent(char[] data, int offs, int length, + boolean generateImpliedPIfNecessary) + { + // Copy the attribute set, don't use the same object because + // it may change + AttributeSet attributes = null; + if (charAttr != null) + attributes = charAttr.copyAttributes(); + + DefaultStyledDocument.ElementSpec element; + element = new DefaultStyledDocument.ElementSpec(attributes, + DefaultStyledDocument.ElementSpec.ContentType, + data, offs, length); + + printBuffer(); + // Add the element to the buffer + parseBuffer.addElement(element); + printBuffer(); + + if (parseBuffer.size() > HTMLDocument.this.getTokenThreshold()) + { + try + { + flush(); + } + catch (BadLocationException ble) + { + // TODO: what to do here? + } + } + } + + /** + * Adds content that is specified in the attribute set. + * + * @param t the HTML.Tag + * @param a the attribute set specifying the special content + */ + protected void addSpecialElement(HTML.Tag t, MutableAttributeSet a) + { + // FIXME: Implement + print ("HTMLReader.addSpecialElement not implemented yet"); + } + + void printBuffer() + { + print ("\n*********BUFFER**********"); + for (int i = 0; i < parseBuffer.size(); i ++) + print (" "+parseBuffer.get(i)); + print ("***************************"); + } + } + + /** + * Gets the reader for the parser to use when loading the document with HTML. + * + * @param pos - the starting position + * @return - the reader + */ + public HTMLEditorKit.ParserCallback getReader(int pos) + { + return new HTMLReader(pos); + } + + /** + * Gets the reader for the parser to use when loading the document with HTML. + * + * @param pos - the starting position + * @param popDepth - the number of EndTagTypes to generate before inserting + * @param pushDepth - the number of StartTagTypes with a direction + * of JoinNextDirection that should be generated before inserting, + * but after the end tags have been generated. + * @param insertTag - the first tag to start inserting into document + * @return - the reader + */ + public HTMLEditorKit.ParserCallback getReader(int pos, + int popDepth, + int pushDepth, + HTML.Tag insertTag) + { + return new HTMLReader(pos, popDepth, pushDepth, insertTag); + } + + /** + * Gets the child element that contains the attribute with the value or null. + * Not thread-safe. + * + * @param e - the element to begin search at + * @param attribute - the desired attribute + * @param value - the desired value + * @return the element found with the attribute and value specified or null + * if it is not found. + */ + public Element getElement(Element e, Object attribute, Object value) + { + if (e != null) + { + if (e.getAttributes().containsAttribute(attribute, value)) + return e; + + int count = e.getElementCount(); + for (int j = 0; j < count; j++) + { + Element child = e.getElement(j); + if (child.getAttributes().containsAttribute(attribute, value)) + return child; + + Element grandChild = getElement(child, attribute, value); + if (grandChild != null) + return grandChild; + } + } + return null; + } + + /** + * Returns the element that has the given id Attribute. If it is not found, + * null is returned. This method works on an Attribute, not a character tag. + * This is not thread-safe. + * + * @param attrId - the Attribute id to look for + * @return the element that has the given id. + */ + public Element getElement(String attrId) + { + Element root = getDefaultRootElement(); + return getElement(root, HTML.getAttributeKey(attrId) , attrId); + } + + /** + * Replaces the children of the given element with the contents of + * the string. The document must have an HTMLEditorKit.Parser set. + * This will be seen as at least two events, n inserts followed by a remove. + * + * @param elem - the brance element whose children will be replaced + * @param htmlText - the string to be parsed and assigned to element. + * @throws BadLocationException + * @throws IOException + * @throws IllegalArgumentException - if elem is a leaf + * @throws IllegalStateException - if an HTMLEditorKit.Parser has not been set + */ + public void setInnerHTML(Element elem, String htmlText) + throws BadLocationException, IOException + { + if (elem.isLeaf()) + throw new IllegalArgumentException("Element is a leaf"); + if (parser == null) + throw new IllegalStateException("Parser has not been set"); + // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit? + System.out.println("setInnerHTML not implemented"); + } + + /** + * Replaces the given element in the parent with the string. When replacing + * a leaf, this will attempt to make sure there is a newline present if one is + * needed. This may result in an additional element being inserted. + * This will be seen as at least two events, n inserts followed by a remove. + * The HTMLEditorKit.Parser must be set. + * + * @param elem - the branch element whose parent will be replaced + * @param htmlText - the string to be parsed and assigned to elem + * @throws BadLocationException + * @throws IOException + * @throws IllegalStateException - if parser is not set + */ + public void setOuterHTML(Element elem, String htmlText) + throws BadLocationException, IOException + { + if (parser == null) + throw new IllegalStateException("Parser has not been set"); + // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit? + System.out.println("setOuterHTML not implemented"); + } + + /** + * Inserts the string before the start of the given element. + * The parser must be set. + * + * @param elem - the element to be the root for the new text. + * @param htmlText - the string to be parsed and assigned to elem + * @throws BadLocationException + * @throws IOException + * @throws IllegalStateException - if parser has not been set + */ + public void insertBeforeStart(Element elem, String htmlText) + throws BadLocationException, IOException + { + if (parser == null) + throw new IllegalStateException("Parser has not been set"); + // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit? + System.out.println("insertBeforeStart not implemented"); + } + + /** + * Inserts the string at the end of the element. If elem's children + * are leaves, and the character at elem.getEndOffset() - 1 is a newline, + * then it will be inserted before the newline. The parser must be set. + * + * @param elem - the element to be the root for the new text + * @param htmlText - the text to insert + * @throws BadLocationException + * @throws IOException + * @throws IllegalStateException - if parser is not set + */ + public void insertBeforeEnd(Element elem, String htmlText) + throws BadLocationException, IOException + { + if (parser == null) + throw new IllegalStateException("Parser has not been set"); + // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit? + System.out.println("insertBeforeEnd not implemented"); + } + + /** + * Inserts the string after the end of the given element. + * The parser must be set. + * + * @param elem - the element to be the root for the new text + * @param htmlText - the text to insert + * @throws BadLocationException + * @throws IOException + * @throws IllegalStateException - if parser is not set + */ + public void insertAfterEnd(Element elem, String htmlText) + throws BadLocationException, IOException + { + if (parser == null) + throw new IllegalStateException("Parser has not been set"); + // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit? + System.out.println("insertAfterEnd not implemented"); + } + + /** + * Inserts the string at the start of the element. + * The parser must be set. + * + * @param elem - the element to be the root for the new text + * @param htmlText - the text to insert + * @throws BadLocationException + * @throws IOException + * @throws IllegalStateException - if parser is not set + */ + public void insertAfterStart(Element elem, String htmlText) + throws BadLocationException, IOException + { + if (parser == null) + throw new IllegalStateException("Parser has not been set"); + // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit? + System.out.println("insertAfterStart not implemented"); + } + + /** + * This method sets the attributes associated with the paragraph containing + * offset. If replace is false, s is merged with existing attributes. The + * length argument determines how many characters are affected by the new + * attributes. This is often the entire paragraph. + * + * @param offset - + * the offset into the paragraph (must be at least 0) + * @param length - + * the number of characters affected (must be at least 0) + * @param s - + * the attributes + * @param replace - + * whether to replace existing attributes, or merge them + */ + public void setParagraphAttributes(int offset, int length, AttributeSet s, + boolean replace) + { + // FIXME: Not implemented. + System.out.println("setParagraphAttributes not implemented"); + super.setParagraphAttributes(offset, length, s, replace); + } + + /** + * This method flags a change in the document. + * + * @param e - the Document event + */ + protected void fireChangedUpdate(DocumentEvent e) + { + // FIXME: Not implemented. + System.out.println("fireChangedUpdate not implemented"); + super.fireChangedUpdate(e); + } + + /** + * This method fires an event intended to be caught by Undo listeners. It + * simply calls the super version inherited from DefaultStyledDocument. With + * this method, an HTML editor could easily provide undo support. + * + * @param e - the UndoableEditEvent + */ + protected void fireUndoableEditUpdate(UndoableEditEvent e) + { + super.fireUndoableEditUpdate(e); } } diff --git a/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java index 5189c777539..1ef9768c923 100644 --- a/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java +++ b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java @@ -38,28 +38,563 @@ exception statement from your version. */ package javax.swing.text.html; + +import java.awt.event.ActionEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionListener; +import java.awt.Cursor; + import java.io.IOException; import java.io.Reader; import java.io.Serializable; +import java.io.StringReader; +import java.io.Writer; +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; + +import javax.swing.Action; +import javax.swing.JEditorPane; +import javax.swing.text.AbstractDocument; import javax.swing.text.BadLocationException; +import javax.swing.text.BoxView; +import javax.swing.text.ComponentView; import javax.swing.text.Document; +import javax.swing.text.EditorKit; +import javax.swing.text.Element; +import javax.swing.text.IconView; +import javax.swing.text.LabelView; import javax.swing.text.MutableAttributeSet; +import javax.swing.text.ParagraphView; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyleContext; import javax.swing.text.StyledEditorKit; +import javax.swing.text.TextAction; +import javax.swing.text.View; +import javax.swing.text.ViewFactory; import javax.swing.text.html.parser.ParserDelegator; /** - * This class is NOT implemented. This file currently holds only - * declarations of the two enclosing classes, necessary for testing - * the implemented javax.swing.text.html.parser package. - * - * @author No authorship is taken, implement the class and be! - * TODO: replace this header after implementing the class. + * @author Lillian Angel (langel at redhat dot com) */ public class HTMLEditorKit extends StyledEditorKit - implements Serializable, Cloneable + implements Serializable, Cloneable, Accessible { + + /** + * Fires the hyperlink events on the associated component + * when needed. + */ + public static class LinkController + extends MouseAdapter + implements MouseMotionListener, Serializable + { + + /** + * Constructor + */ + public LinkController() + { + super(); + } + + /** + * Dispatched when the mouse is clicked. If the component + * is read-only, then the clicked event is used to drive an + * attempt to follow the reference specified by a link + * + * @param e - the mouse event + */ + public void mouseClicked(MouseEvent e) + { + /* + These MouseInputAdapter methods generate mouse appropriate events around + hyperlinks (entering, exiting, and activating). + */ + // FIXME: Not implemented. + } + + /** + * Dispatched when the mouse is dragged on a component. + * + * @param e - the mouse event. + */ + public void mouseDragged(MouseEvent e) + { + /* + These MouseInputAdapter methods generate mouse appropriate events around + hyperlinks (entering, exiting, and activating). + */ + // FIXME: Not implemented. + } + + /** + * Dispatched when the mouse cursor has moved into the component. + * + * @param e - the mouse event. + */ + public void mouseMoved(MouseEvent e) + { + /* + These MouseInputAdapter methods generate mouse appropriate events around + hyperlinks (entering, exiting, and activating). + */ + // FIXME: Not implemented. + } + + /** + * If the given position represents a link, then linkActivated is called + * on the JEditorPane. Implemented to forward to the method with the same + * name, but pos == editor == -1. + * + * @param pos - the position + * @param editor - the editor pane + */ + protected void activateLink(int pos, + JEditorPane editor) + { + /* + This method creates and fires a HyperlinkEvent if the document is an + instance of HTMLDocument and the href tag of the link is not null. + */ + // FIXME: Not implemented. + } + } + + /** + * This class is used to insert a string of HTML into an existing + * document. At least 2 HTML.Tags need to be supplied. The first Tag (parentTag) + * identifies the parent in the document to add the elements to. The second, (addTag), + * identifies that the first tag should be added to the document as seen in the string. + * The parser will generate all appropriate (opening/closing tags_ even if they are not + * in the HTML string passed in. + */ + public static class InsertHTMLTextAction + extends HTMLTextAction + { + + /** + * Tag in HTML to start adding tags from. + */ + protected HTML.Tag addTag; + + /** + * Alternate tag in HTML to start adding tags from if parentTag is + * not found and alternateParentTag is not found. + */ + protected HTML.Tag alternateAddTag; + + /** + * Alternate tag to check if parentTag is not found. + */ + protected HTML.Tag alternateParentTag; + + /** + * HTML to insert. + */ + protected String html; + + /** + * Tag to check for in the document. + */ + protected HTML.Tag parentTag; + + /** + * Initializes all fields. + * + * @param name - the name of the document. + * @param html - the html to insert + * @param parentTag - the parent tag to check for + * @param addTag - the tag to start adding from + */ + public InsertHTMLTextAction(String name, String html, + HTML.Tag parentTag, HTML.Tag addTag) + { + this(name, html, parentTag, addTag, null, null); + } + + /** + * Initializes all fields and calls super + * + * @param name - the name of the document. + * @param html - the html to insert + * @param parentTag - the parent tag to check for + * @param addTag - the tag to start adding from + * @param alternateParentTag - the alternate parent tag + * @param alternateAddTag - the alternate add tag + */ + public InsertHTMLTextAction(String name, String html, HTML.Tag parentTag, + HTML.Tag addTag, HTML.Tag alternateParentTag, + HTML.Tag alternateAddTag) + { + super(name); + // Fields are for easy access when the action is applied to an actual + // document. + this.html = html; + this.parentTag = parentTag; + this.addTag = addTag; + this.alternateParentTag = alternateParentTag; + this.alternateAddTag = alternateAddTag; + } + + /** + * HTMLEditorKit.insertHTML is called. If an exception is + * thrown, it is wrapped in a RuntimeException and thrown. + * + * @param editor - the editor to use to get the editorkit + * @param doc - + * the Document to insert the HTML into. + * @param offset - + * where to begin inserting the HTML. + * @param html - + * the String to insert + * @param popDepth - + * the number of ElementSpec.EndTagTypes to generate before + * inserting + * @param pushDepth - + * the number of ElementSpec.StartTagTypes with a direction of + * ElementSpec.JoinNextDirection that should be generated before + * @param addTag - + * the first tag to start inserting into document + */ + protected void insertHTML(JEditorPane editor, HTMLDocument doc, int offset, + String html, int popDepth, int pushDepth, + HTML.Tag addTag) + { + try + { + super.getHTMLEditorKit(editor).insertHTML(doc, offset, html, + popDepth, pushDepth, addTag); + } + catch (IOException e) + { + throw (RuntimeException) new RuntimeException("Parser is null.").initCause(e); + } + catch (BadLocationException ex) + { + throw (RuntimeException) new RuntimeException("BadLocationException: " + + offset).initCause(ex); + } + } + + /** + * Invoked when inserting at a boundary. Determines the number of pops, + * and then the number of pushes that need to be performed. The it calls + * insertHTML. + * + * @param editor - + * the editor to use to get the editorkit + * @param doc - + * the Document to insert the HTML into. + * @param offset - + * where to begin inserting the HTML. + * @param insertElement - + * the element to insert + * @param html - + * the html to insert + * @param parentTag - + * the parent tag + * @param addTag - + * the first tag + */ + protected void insertAtBoundary(JEditorPane editor, + HTMLDocument doc, int offset, + Element insertElement, + String html, HTML.Tag parentTag, + HTML.Tag addTag) + { + /* + As its name implies, this protected method is used when HTML is inserted at a + boundary. (A boundary in this case is an offset in doc that exactly matches the + beginning offset of the parentTag.) It performs the extra work required to keep + the tag stack in shape and then calls insertHTML(). The editor and doc argu- + ments are the editor pane and document where the HTML should go. The offset + argument represents the cursor location or selection start in doc. The insert- + Element and parentTag arguments are used to calculate the proper number of + tag pops and pushes before inserting the HTML (via html and addTag, which are + passed directly to insertHTML()). + */ + // FIXME: not implemented + } + + /** + * Invoked when inserting at a boundary. Determines the number of pops, + * and then the number of pushes that need to be performed. The it calls + * insertHTML. + * + * @param editor - the editor to use to get the editorkit + * @param doc - + * the Document to insert the HTML into. + * @param offset - + * where to begin inserting the HTML. + * @param insertElement - the element to insert + * @param html - the html to insert + * @param parentTag - the parent tag + * @param addTag - the first tag + * + * @deprecated as of v1.3, use insertAtBoundary + */ + protected void insertAtBoundry(JEditorPane editor, + HTMLDocument doc, + int offset, Element insertElement, + String html, HTML.Tag parentTag, + HTML.Tag addTag) + { + insertAtBoundary(editor, doc, offset, insertElement, + html, parentTag, addTag); + } + + /** + * Inserts the HTML. + * + * @param ae - the action performed + */ + public void actionPerformed(ActionEvent ae) + { + Object source = ae.getSource(); + if (source instanceof JEditorPane) + { + JEditorPane pane = ((JEditorPane) source); + Document d = pane.getDocument(); + if (d instanceof HTMLDocument) + insertHTML(pane, (HTMLDocument) d, 0, html, 0, 0, addTag); + // FIXME: is this correct parameters? + } + // FIXME: else not implemented + } + } + + /** + * Abstract Action class that helps inserting HTML into an existing document. + */ + public abstract static class HTMLTextAction + extends StyledEditorKit.StyledTextAction + { + + /** + * Constructor + */ + public HTMLTextAction(String name) + { + super(name); + } + + /** + * Gets the HTMLDocument from the JEditorPane. + * + * @param e - the editor pane + * @return the html document. + */ + protected HTMLDocument getHTMLDocument(JEditorPane e) + { + Document d = e.getDocument(); + if (d instanceof HTMLDocument) + return (HTMLDocument) d; + throw new IllegalArgumentException("Document is not a HTMLDocument."); + } + + /** + * Gets the HTMLEditorKit + * + * @param e - the JEditorPane to get the HTMLEditorKit from. + * @return the HTMLEditorKit + */ + protected HTMLEditorKit getHTMLEditorKit(JEditorPane e) + { + EditorKit d = e.getEditorKit(); + if (d instanceof HTMLEditorKit) + return (HTMLEditorKit) d; + throw new IllegalArgumentException("EditorKit is not a HTMLEditorKit."); + } + + /** + * Returns an array of Elements that contain the offset. + * The first elements corresponds to the roots of the doc. + * + * @param doc - the document to get the Elements from. + * @param offset - the offset the Elements must contain + * @return an array of all the elements containing the offset. + */ + protected Element[] getElementsAt(HTMLDocument doc, + int offset) + { + return getElementsAt(doc.getDefaultRootElement(), offset, 0); + } + + /** + * Helper function to get all elements using recursion. + */ + private Element[] getElementsAt(Element root, int offset, int depth) + { + Element[] elements = null; + if (root != null) + { + if (root.isLeaf()) + { + elements = new Element[depth + 1]; + elements[depth] = root; + return elements; + } + elements = getElementsAt(root.getElement(root.getElementIndex(offset)), + offset, depth + 1); + elements[depth] = root; + } + return elements; + } + + /** + * Returns the number of elements, starting at the deepest point, needed + * to get an element representing tag. -1 if no elements are found, 0 if + * the parent of the leaf at offset represents the tag. + * + * @param doc - + * the document to search + * @param offset - + * the offset to check + * @param tag - + * the tag to look for + * @return - the number of elements needed to get an element representing + * tag. + */ + protected int elementCountToTag(HTMLDocument doc, + int offset, HTML.Tag tag) + { + Element root = doc.getDefaultRootElement(); + int num = -1; + Element next = root.getElement(root.getElementIndex(offset)); + + while (!next.isLeaf()) + { + num++; + if (next.getAttributes(). + getAttribute(StyleConstants.NameAttribute).equals(tag)) + return num; + next = next.getElement(next.getElementIndex(offset)); + } + return num; + } + + /** + * Gets the deepest element at offset with the + * matching tag. + * + * @param doc - the document to search + * @param offset - the offset to check for + * @param tag - the tag to match + * @return - the element that is found, null if not found. + */ + protected Element findElementMatchingTag(HTMLDocument doc, + int offset, HTML.Tag tag) + { + Element element = doc.getDefaultRootElement(); + Element tagElement = null; + + while (element != null) + { + Object otag = element.getAttributes().getAttribute( + StyleConstants.NameAttribute); + if (otag instanceof HTML.Tag && otag.equals(tag)) + tagElement = element; + element = element.getElement(element.getElementIndex(offset)); + } + + return tagElement; + } + } + + /** + * A {@link ViewFactory} that is able to create {@link View}s for + * the <code>Element</code>s that are supported. + */ + public static class HTMLFactory + implements ViewFactory + { + + /** + * Constructor + */ + public HTMLFactory() + { + // Do Nothing here. + } + + /** + * Creates a {@link View} for the specified <code>Element</code>. + * + * @param element the <code>Element</code> to create a <code>View</code> + * for + * @return the <code>View</code> for the specified <code>Element</code> + * or <code>null</code> if the type of <code>element</code> is + * not supported + */ + public View create(Element element) + { + View view = null; + Object attr = element.getAttributes().getAttribute( + StyleConstants.NameAttribute); + if (attr instanceof HTML.Tag) + { + HTML.Tag tag = (HTML.Tag) attr; + + if (tag.equals(HTML.Tag.IMPLIED) || tag.equals(HTML.Tag.P) + || tag.equals(HTML.Tag.H1) || tag.equals(HTML.Tag.H2) + || tag.equals(HTML.Tag.H3) || tag.equals(HTML.Tag.H4) + || tag.equals(HTML.Tag.H5) || tag.equals(HTML.Tag.H6) + || tag.equals(HTML.Tag.DT)) + view = new ParagraphView(element); + else if (tag.equals(HTML.Tag.LI) || tag.equals(HTML.Tag.DL) + || tag.equals(HTML.Tag.DD) || tag.equals(HTML.Tag.BODY) + || tag.equals(HTML.Tag.HTML) || tag.equals(HTML.Tag.CENTER) + || tag.equals(HTML.Tag.DIV) + || tag.equals(HTML.Tag.BLOCKQUOTE) + || tag.equals(HTML.Tag.PRE)) + view = new BlockView(element, View.Y_AXIS); + + // FIXME: Uncomment when the views have been implemented + /* else if (tag.equals(HTML.Tag.CONTENT)) + view = new InlineView(element); + else if (tag.equals(HTML.Tag.MENU) || tag.equals(HTML.Tag.DIR) + || tag.equals(HTML.Tag.UL) || tag.equals(HTML.Tag.OL)) + view = new ListView(element); + else if (tag.equals(HTML.Tag.IMG)) + view = new ImageView(element); + else if (tag.equals(HTML.Tag.HR)) + view = new HRuleView(element); + else if (tag.equals(HTML.Tag.BR)) + view = new BRView(element); + else if (tag.equals(HTML.Tag.TABLE)) + view = new TableView(element); + else if (tag.equals(HTML.Tag.INPUT) || tag.equals(HTML.Tag.SELECT) + || tag.equals(HTML.Tag.TEXTAREA)) + view = new FormView(element); + else if (tag.equals(HTML.Tag.OBJECT)) + view = new ObjectView(element); + else if (tag.equals(HTML.Tag.FRAMESET)) + view = new FrameSetView(element); + else if (tag.equals(HTML.Tag.FRAME)) + view = new FrameView(element); */ + } + + if (view == null) + { + String name = element.getName(); + if (name.equals(AbstractDocument.ContentElementName)) + view = new LabelView(element); + else if (name.equals(AbstractDocument.ParagraphElementName)) + view = new ParagraphView(element); + else if (name.equals(AbstractDocument.SectionElementName)) + view = new BoxView(element, View.Y_AXIS); + else if (name.equals(StyleConstants.ComponentElementName)) + view = new ComponentView(element); + else if (name.equals(StyleConstants.IconElementName)) + view = new IconView(element); + } + return view; + } + } + /** * The abstract HTML parser declaration. */ @@ -76,9 +611,7 @@ public class HTMLEditorKit * @throws IOException, normally if the reader throws one. */ public abstract void parse(Reader reader, ParserCallback callback, - boolean ignoreCharSet - ) - throws IOException; + boolean ignoreCharSet) throws IOException; } /** @@ -96,11 +629,19 @@ public class HTMLEditorKit public static final Object IMPLIED = "_implied_"; /** + * Constructor + */ + public ParserCallback() + { + // Nothing to do here. + } + + /** * The parser calls this method after it finishes parsing the document. */ public void flush() throws BadLocationException { - // TODO: What to do here, if anything? + // Nothing to do here. } /** @@ -110,7 +651,7 @@ public class HTMLEditorKit */ public void handleComment(char[] comment, int position) { - // TODO: What to do here, if anything? + // Nothing to do here. } /** @@ -121,7 +662,7 @@ public class HTMLEditorKit */ public void handleEndOfLineString(String end_of_line) { - // TODO: What to do here, if anything? + // Nothing to do here. } /** @@ -133,7 +674,7 @@ public class HTMLEditorKit */ public void handleEndTag(HTML.Tag tag, int position) { - // TODO: What to do here, if anything? + // Nothing to do here. } /** @@ -144,7 +685,7 @@ public class HTMLEditorKit */ public void handleError(String message, int position) { - // TODO: What to do here, if anything? + // Nothing to do here. } /** @@ -157,7 +698,7 @@ public class HTMLEditorKit public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet attributes, int position) { - // TODO: What to do here, if anything? + // Nothing to do here. } /** @@ -168,10 +709,9 @@ public class HTMLEditorKit * @param position The tag position in the text being parsed */ public void handleStartTag(HTML.Tag tag, MutableAttributeSet attributes, - int position - ) + int position) { - // TODO: What to do here, if anything? + // Nothing to do here. } /** @@ -181,7 +721,7 @@ public class HTMLEditorKit */ public void handleText(char[] text, int position) { - // TODO: What to do here, if anything? + // Nothing to do here. } } @@ -255,7 +795,83 @@ public class HTMLEditorKit * The "ident paragraph right" action. */ public static final String PARA_INDENT_RIGHT = "html-para-indent-right"; - + + /** + * Actions for HTML + */ + private static final Action[] defaultActions = { + // FIXME: Add default actions for html + }; + + /** + * The current style sheet. + */ + StyleSheet styleSheet; + + /** + * The ViewFactory for HTMLFactory. + */ + HTMLFactory viewFactory; + + /** + * The Cursor for links. + */ + Cursor linkCursor; + + /** + * The default cursor. + */ + Cursor defaultCursor; + + /** + * The parser. + */ + Parser parser; + + /** + * The mouse listener used for links. + */ + LinkController mouseListener; + + /** + * Style context for this editor. + */ + StyleContext styleContext; + + /** The content type */ + String contentType = "text/html"; + + /** The input attributes defined by default.css */ + MutableAttributeSet inputAttributes; + + /** The editor pane used. */ + JEditorPane editorPane; + + /** + * Constructs an HTMLEditorKit, creates a StyleContext, and loads the style sheet. + */ + public HTMLEditorKit() + { + super(); + styleContext = new StyleContext(); + styleSheet = new StyleSheet(); + styleSheet.importStyleSheet(getClass().getResource(DEFAULT_CSS)); + // FIXME: Set inputAttributes with default.css + } + + /** + * Gets a factory suitable for producing views of any + * models that are produced by this kit. + * + * @return the view factory suitable for producing views. + */ + public ViewFactory getViewFactory() + { + if (viewFactory == null) + viewFactory = new HTMLFactory(); + return viewFactory; + } + /** * Create a text storage model for this type of editor. * @@ -263,18 +879,297 @@ public class HTMLEditorKit */ public Document createDefaultDocument() { - HTMLDocument document = new HTMLDocument(); + HTMLDocument document = new HTMLDocument(getStyleSheet()); + document.setParser(getParser()); return document; } /** * Get the parser that this editor kit uses for reading HTML streams. This * method can be overridden to use the alternative parser. - * + * * @return the HTML parser (by default, {@link ParserDelegator}). */ protected Parser getParser() { - return new ParserDelegator(); + if (parser == null) + parser = new ParserDelegator(); + return parser; + } + + /** + * Inserts HTML into an existing document. + * + * @param doc - the Document to insert the HTML into. + * @param offset - where to begin inserting the HTML. + * @param html - the String to insert + * @param popDepth - the number of ElementSpec.EndTagTypes + * to generate before inserting + * @param pushDepth - the number of ElementSpec.StartTagTypes + * with a direction of ElementSpec.JoinNextDirection that + * should be generated before + * @param insertTag - the first tag to start inserting into document + * @throws IOException - on any I/O error + * @throws BadLocationException - if pos represents an invalid location + * within the document + */ + public void insertHTML(HTMLDocument doc, int offset, String html, + int popDepth, int pushDepth, HTML.Tag insertTag) + throws BadLocationException, IOException + { + Parser parser = getParser(); + if (offset < 0 || offset > doc.getLength()) + throw new BadLocationException("Bad location", offset); + if (parser == null) + throw new IOException("Parser is null."); + + ParserCallback pc = ((HTMLDocument) doc).getReader + (offset, popDepth, pushDepth, insertTag); + + // FIXME: What should ignoreCharSet be set to? + + // parser.parse inserts html into the buffer + parser.parse(new StringReader(html), pc, false); + pc.flush(); + } + + /** + * Inserts content from the given stream. Inserting HTML into a non-empty + * document must be inside the body Element, if you do not insert into + * the body an exception will be thrown. When inserting into a non-empty + * document all tags outside of the body (head, title) will be dropped. + * + * @param in - the stream to read from + * @param doc - the destination for the insertion + * @param pos - the location in the document to place the content + * @throws IOException - on any I/O error + * @throws BadLocationException - if pos represents an invalid location + * within the document + */ + public void read(Reader in, Document doc, int pos) throws IOException, + BadLocationException + { + if (doc instanceof HTMLDocument) + { + Parser parser = getParser(); + if (pos < 0 || pos > doc.getLength()) + throw new BadLocationException("Bad location", pos); + if (parser == null) + throw new IOException("Parser is null."); + + HTMLDocument hd = ((HTMLDocument) doc); + hd.setBase(editorPane.getPage()); + ParserCallback pc = hd.getReader(pos); + + // FIXME: What should ignoreCharSet be set to? + + // parser.parse inserts html into the buffer + parser.parse(in, pc, false); + pc.flush(); + } + else + // read in DefaultEditorKit is called. + // the string is inserted in the document as usual. + super.read(in, doc, pos); + } + + /** + * Writes content from a document to the given stream in + * an appropriate format. + * + * @param out - the stream to write to + * @param doc - the source for the write + * @param pos - the location in the document to get the content. + * @param len - the amount to write out + * @throws IOException - on any I/O error + * @throws BadLocationException - if pos represents an invalid location + * within the document + */ + public void write(Writer out, Document doc, int pos, int len) + throws IOException, BadLocationException + { + if (doc instanceof HTMLDocument) + { + // FIXME: Not implemented. Use HTMLWriter. + out.write(doc.getText(pos, len)); + } + else + super.write(out, doc, pos, len); + } + + /** + * Gets the content type that the kit supports. + * This kit supports the type text/html. + * + * @returns the content type supported. + */ + public String getContentType() + { + return contentType; + } + + /** + * Creates a copy of the editor kit. + * + * @return a copy of this. + */ + public Object clone() + { + // FIXME: Need to clone all fields + return (HTMLEditorKit) super.clone(); + } + + /** + * Copies the key/values in elements AttributeSet into set. + * This does not copy component, icon, or element names attributes. + * This is called anytime the caret moves over a different location. + * + * @param element - the element to create the input attributes for. + * @param set - the set to copy the values into. + */ + protected void createInputAttributes(Element element, + MutableAttributeSet set) + { + set.removeAttributes(set); + set.addAttributes(element.getAttributes()); + // FIXME: Not fully implemented. + } + + /** + * Called when this is installed into the JEditorPane. + * + * @param c - the JEditorPane installed into. + */ + public void install(JEditorPane c) + { + super.install(c); + mouseListener = new LinkController(); + c.addMouseListener(mouseListener); + editorPane = c; + // FIXME: need to set up hyperlinklistener object + } + + /** + * Called when the this is removed from the JEditorPane. + * It unregisters any listeners. + * + * @param c - the JEditorPane being removed from. + */ + public void deinstall(JEditorPane c) + { + super.deinstall(c); + c.removeMouseListener(mouseListener); + mouseListener = null; + editorPane = null; + } + + /** + * Gets the AccessibleContext associated with this. + * + * @return the AccessibleContext for this. + */ + public AccessibleContext getAccessibleContext() + { + // FIXME: Should return an instance of + // javax.swing.text.html.AccessibleHTML$RootHTMLAccessibleContext + // Not implemented yet. + return null; + } + + /** + * Gets the action list. This list is supported by the superclass + * augmented by the collection of actions defined locally for style + * operations. + * + * @return an array of all the actions + */ + public Action[] getActions() + { + return TextAction.augmentList(super.getActions(), defaultActions); + } + + /** + * Returns the default cursor. + * + * @return the default cursor + */ + public Cursor getDefaultCursor() + { + if (defaultCursor == null) + defaultCursor = Cursor.getDefaultCursor(); + return defaultCursor; + } + + /** + * Returns the cursor for links. + * + * @return the cursor for links. + */ + public Cursor getLinkCursor() + { + if (linkCursor == null) + linkCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); + return linkCursor; + } + + /** + * Sets the Cursor for links. + * + * @param cursor - the new cursor for links. + */ + public void setLinkCursor(Cursor cursor) + { + linkCursor = cursor; + } + + /** + * Sets the default cursor. + * + * @param cursor - the new default cursor. + */ + public void setDefaultCursor(Cursor cursor) + { + defaultCursor = cursor; + } + + /** + * Gets the input attributes used for the styled editing actions. + * + * @return the attribute set + */ + public MutableAttributeSet getInputAttributes() + { + return inputAttributes; + } + + /** + * Get the set of styles currently being used to render the HTML elements. + * By default the resource specified by DEFAULT_CSS gets loaded, and is + * shared by all HTMLEditorKit instances. + * + * @return the style sheet. + */ + public StyleSheet getStyleSheet() + { + if (styleSheet == null) + { + styleSheet = new StyleSheet(); + styleSheet.importStyleSheet(getClass().getResource(DEFAULT_CSS)); + } + return styleSheet; + } + + /** + * Set the set of styles to be used to render the various HTML elements. + * These styles are specified in terms of CSS specifications. Each document + * produced by the kit will have a copy of the sheet which it can add the + * document specific styles to. By default, the StyleSheet specified is shared + * by all HTMLEditorKit instances. + * + * @param s - the new style sheet + */ + public void setStyleSheet(StyleSheet s) + { + styleSheet = s; } -}
\ No newline at end of file +} diff --git a/libjava/classpath/javax/swing/text/html/StyleSheet.java b/libjava/classpath/javax/swing/text/html/StyleSheet.java new file mode 100644 index 00000000000..2466a2808fe --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/StyleSheet.java @@ -0,0 +1,937 @@ +/* StyleSheet.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; + +import java.io.IOException; +import java.io.Reader; +import java.io.Serializable; +import java.io.StringReader; + +import java.net.MalformedURLException; +import java.net.URL; + +import java.util.Enumeration; +import java.util.Vector; + +import javax.swing.text.AttributeSet; +import javax.swing.text.Element; +import javax.swing.text.MutableAttributeSet; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.Style; +import javax.swing.text.StyleContext; +import javax.swing.text.View; + + +/** + * This class adds support for defining the visual characteristics of HTML views + * being rendered. This enables views to be customized by a look-and-feel, mulitple + * views over the same model can be rendered differently. Each EditorPane has its + * own StyleSheet, but by default one sheet will be shared by all of the HTMLEditorKit + * instances. An HTMLDocument can also have a StyleSheet, which holds specific CSS + * specs. + * + * In order for Views to store less state and therefore be more lightweight, + * the StyleSheet can act as a factory for painters that handle some of the + * rendering tasks. Since the StyleSheet may be used by views over multiple + * documents the HTML attributes don't effect the selector being used. + * + * The rules are stored as named styles, and other information is stored to + * translate the context of an element to a rule. + * + * @author Lillian Angel (langel@redhat.com) + */ +public class StyleSheet extends StyleContext +{ + + /** The base URL */ + URL base; + + /** Base font size (int) */ + int baseFontSize; + + /** The style sheets stored. */ + StyleSheet[] styleSheet; + + /** + * Constructs a StyleSheet. + */ + public StyleSheet() + { + super(); + baseFontSize = 4; // Default font size from CSS + } + + /** + * Gets the style used to render the given tag. The element represents the tag + * and can be used to determine the nesting, where the attributes will differ + * if there is nesting inside of elements. + * + * @param t - the tag to translate to visual attributes + * @param e - the element representing the tag + * @return the set of CSS attributes to use to render the tag. + */ + public Style getRule(HTML.Tag t, Element e) + { + // FIXME: Not implemented. + return null; + } + + /** + * Gets the rule that best matches the selector. selector is a space + * separated String of element names. The attributes of the returned + * Style will change as rules are added and removed. + * + * @param selector - the element names separated by spaces + * @return the set of CSS attributes to use to render + */ + public Style getRule(String selector) + { + // FIXME: Not implemented. + return null; + } + + /** + * Adds a set if rules to the sheet. The rules are expected to be in valid + * CSS format. This is called as a result of parsing a <style> tag + * + * @param rule - the rule to add to the sheet + */ + public void addRule(String rule) + { + CssParser cp = new CssParser(); + try + { + cp.parse(base, new StringReader(rule), false, false); + } + catch (IOException io) + { + // Do nothing here. + } + } + + /** + * Translates a CSS declaration into an AttributeSet. This is called + * as a result of encountering an HTML style attribute. + * + * @param decl - the declaration to get + * @return the AttributeSet representing the declaration + */ + public AttributeSet getDeclaration(String decl) + { + if (decl == null) + return SimpleAttributeSet.EMPTY; + // FIXME: Not implemented. + return null; + } + + /** + * Loads a set of rules that have been specified in terms of CSS grammar. + * If there are any conflicts with existing rules, the new rule is added. + * + * @param in - the stream to read the CSS grammar from. + * @param ref - the reference URL. It is the location of the stream, it may + * be null. All relative URLs specified in the stream will be based upon this + * parameter. + * @throws IOException - For any IO error while reading + */ + public void loadRules(Reader in, URL ref) throws IOException + { + CssParser cp = new CssParser(); + cp.parse(ref, in, false, false); + } + + /** + * Gets a set of attributes to use in the view. This is a set of + * attributes that can be used for View.getAttributes + * + * @param v - the view to get the set for + * @return the AttributeSet to use in the view. + */ + public AttributeSet getViewAttributes(View v) + { + // FIXME: Not implemented. + return null; + } + + /** + * Removes a style previously added. + * + * @param nm - the name of the style to remove + */ + public void removeStyle(String nm) + { + // FIXME: Not implemented. + super.removeStyle(nm); + } + + /** + * Adds the rules from ss to those of the receiver. ss's rules will + * override the old rules. An added StyleSheet will never override the rules + * of the receiving style sheet. + * + * @param ss - the new StyleSheet. + */ + public void addStyleSheet(StyleSheet ss) + { + if (styleSheet == null) + styleSheet = new StyleSheet[] {ss}; + else + System.arraycopy(new StyleSheet[] {ss}, 0, styleSheet, + styleSheet.length, 1); + } + + /** + * Removes ss from those of the receiver + * + * @param ss - the StyleSheet to remove. + */ + public void removeStyleSheet(StyleSheet ss) + { + if (styleSheet.length == 1 && styleSheet[0].equals(ss)) + styleSheet = null; + else + { + for (int i = 0; i < styleSheet.length; i++) + { + StyleSheet curr = styleSheet[i]; + if (curr.equals(ss)) + { + StyleSheet[] tmp = new StyleSheet[styleSheet.length - 1]; + if (i != 0 && i != (styleSheet.length - 1)) + { + System.arraycopy(styleSheet, 0, tmp, 0, i); + System.arraycopy(styleSheet, i + 1, tmp, i, + styleSheet.length - i - 1); + } + else if (i == 0) + System.arraycopy(styleSheet, 1, tmp, 0, styleSheet.length - 1); + else + System.arraycopy(styleSheet, 0, tmp, 0, styleSheet.length - 1); + + styleSheet = tmp; + break; + } + } + } + } + + /** + * Returns an array of the linked StyleSheets. May return null. + * + * @return - An array of the linked StyleSheets. + */ + public StyleSheet[] getStyleSheets() + { + return styleSheet; + } + + /** + * Imports a style sheet from the url. The rules are directly added to the + * receiver. + * + * @param url - the URL to import the StyleSheet from. + */ + public void importStyleSheet(URL url) + { + // FIXME: Not implemented + } + + /** + * Sets the base url. All import statements that are relative, will be + * relative to base. + * + * @param base - + * the base URL. + */ + public void setBase(URL base) + { + this.base = base; + } + + /** + * Gets the base url. + * + * @return - the base + */ + public URL getBase() + { + return base; + } + + /** + * Adds a CSS attribute to the given set. + * + * @param attr - the attribute set + * @param key - the attribute to add + * @param value - the value of the key + */ + public void addCSSAttribute(MutableAttributeSet attr, CSS.Attribute key, + String value) + { + attr.addAttribute(key, value); + } + + /** + * Adds a CSS attribute to the given set. + * This method parses the value argument from HTML based on key. + * Returns true if it finds a valid value for the given key, + * and false otherwise. + * + * @param attr - the attribute set + * @param key - the attribute to add + * @param value - the value of the key + * @return true if a valid value was found. + */ + public boolean addCSSAttributeFromHTML(MutableAttributeSet attr, CSS.Attribute key, + String value) + { + // FIXME: Need to parse value from HTML based on key. + attr.addAttribute(key, value); + return attr.containsAttribute(key, value); + } + + /** + * Converts a set of HTML attributes to an equivalent set of CSS attributes. + * + * @param htmlAttrSet - the set containing the HTML attributes. + * @return the set of CSS attributes + */ + public AttributeSet translateHTMLToCSS(AttributeSet htmlAttrSet) + { + // FIXME: Not implemented. + return null; + } + + /** + * Adds an attribute to the given set and returns a new set. This is implemented + * to convert StyleConstants attributes to CSS before forwarding them to the superclass. + * The StyleConstants attribute do not have corresponding CSS entry, the attribute + * is stored (but will likely not be used). + * + * @param old - the old set + * @param key - the non-null attribute key + * @param value - the attribute value + * @return the updated set + */ + public AttributeSet addAttribute(AttributeSet old, Object key, + Object value) + { + // FIXME: Not implemented. + return super.addAttribute(old, key, value); + } + + /** + * Adds a set of attributes to the element. If any of these attributes are + * StyleConstants, they will be converted to CSS before forwarding to the + * superclass. + * + * @param old - the old set + * @param attr - the attributes to add + * @return the updated attribute set + */ + public AttributeSet addAttributes(AttributeSet old, AttributeSet attr) + { + // FIXME: Not implemented. + return super.addAttributes(old, attr); + } + + /** + * Removes an attribute from the set. If the attribute is a + * StyleConstants, it will be converted to CSS before forwarding to the + * superclass. + * + * @param old - the old set + * @param key - the non-null attribute key + * @return the updated set + */ + public AttributeSet removeAttribute(AttributeSet old, Object key) + { + // FIXME: Not implemented. + return super.removeAttribute(old, key); + } + + /** + * Removes an attribute from the set. If any of the attributes are + * StyleConstants, they will be converted to CSS before forwarding to the + * superclass. + * + * @param old - the old set + * @param attrs - the attributes to remove + * @return the updated set + */ + public AttributeSet removeAttributes(AttributeSet old, AttributeSet attrs) + { + // FIXME: Not implemented. + return super.removeAttributes(old, attrs); + } + + /** + * Removes a set of attributes for the element. If any of the attributes is a + * StyleConstants, they will be converted to CSS before forwarding to the + * superclass. + * + * @param old - the old attribute set + * @param names - the attribute names + * @return the update attribute set + */ + public AttributeSet removeAttributes(AttributeSet old, Enumeration names) + { + // FIXME: Not implemented. + return super.removeAttributes(old, names); + } + + /** + * Creates a compact set of attributes that might be shared. This is a hook + * for subclasses that want to change the behaviour of SmallAttributeSet. + * + * @param a - the set of attributes to be represented in the compact form. + * @return the set of attributes created + */ + protected StyleContext.SmallAttributeSet createSmallAttributeSet(AttributeSet a) + { + return super.createSmallAttributeSet(a); + } + + /** + * Creates a large set of attributes. This set is not shared. This is a hook + * for subclasses that want to change the behaviour of the larger attribute + * storage format. + * + * @param a - the set of attributes to be represented in the larger form. + * @return the large set of attributes. + */ + protected MutableAttributeSet createLargeAttributeSet(AttributeSet a) + { + return super.createLargeAttributeSet(a); + } + + /** + * Gets the font to use for the given set. + * + * @param a - the set to get the font for. + * @return the font for the set + */ + public Font getFont(AttributeSet a) + { + return super.getFont(a); + } + + /** + * Takes a set of attributes and turns it into a foreground + * color specification. This is used to specify things like, brigher, more hue + * etc. + * + * @param a - the set to get the foreground color for + * @return the foreground color for the set + */ + public Color getForeground(AttributeSet a) + { + return super.getForeground(a); + } + + /** + * Takes a set of attributes and turns it into a background + * color specification. This is used to specify things like, brigher, more hue + * etc. + * + * @param a - the set to get the background color for + * @return the background color for the set + */ + public Color getBackground(AttributeSet a) + { + return super.getBackground(a); + } + + /** + * Gets the box formatter to use for the given set of CSS attributes. + * + * @param a - the given set + * @return the box formatter + */ + public BoxPainter getBoxPainter(AttributeSet a) + { + return new BoxPainter(a); + } + + /** + * Gets the list formatter to use for the given set of CSS attributes. + * + * @param a - the given set + * @return the list formatter + */ + public ListPainter getListPainter(AttributeSet a) + { + return new ListPainter(a); + } + + /** + * Sets the base font size between 1 and 7. + * + * @param sz - the new font size for the base. + */ + public void setBaseFontSize(int sz) + { + if (sz <= 7 && sz >= 1) + baseFontSize = sz; + } + + /** + * Sets the base font size from the String. It can either identify + * a specific font size (between 1 and 7) or identify a relative + * font size such as +1 or -2. + * + * @param size - the new font size as a String. + */ + public void setBaseFontSize(String size) + { + size.trim(); + int temp = 0; + try + { + if (size.length() == 2) + { + int i = new Integer(size.substring(1)).intValue(); + if (size.startsWith("+")) + temp = baseFontSize + i; + else if (size.startsWith("-")) + temp = baseFontSize - i; + } + else if (size.length() == 1) + temp = new Integer(size.substring(0)).intValue(); + + if (temp <= 7 && temp >= 1) + baseFontSize = temp; + } + catch (NumberFormatException nfe) + { + // Do nothing here + } + } + + /** + * TODO + * + * @param pt - TODO + * @return TODO + */ + public static int getIndexOfSize(float pt) + { + // FIXME: Not implemented. + return 0; + } + + /** + * Gets the point size, given a size index. + * + * @param index - the size index + * @return the point size. + */ + public float getPointSize(int index) + { + // FIXME: Not implemented. + return 0; + } + + /** + * Given the string of the size, returns the point size value. + * + * @param size - the string representation of the size. + * @return - the point size value. + */ + public float getPointSize(String size) + { + // FIXME: Not implemented. + return 0; + } + + /** + * Converst a color string to a color. If it is not found, null is returned. + * + * @param color - the color string such as "RED" or "#NNNNNN" + * @return the Color, or null if not found. + */ + public Color stringToColor(String color) + { + color = color.toLowerCase(); + if (color.equals("black") || color.equals("#000000")) + return Color.BLACK; + else if (color.equals("aqua") || color.equals("#00FFFF")) + return new Color(127, 255, 212); + else if (color.equals("gray") || color.equals("#808080")) + return Color.GRAY; + else if (color.equals("navy") || color.equals("#000080")) + return new Color(0, 0, 128); + else if (color.equals("silver") || color.equals("#C0C0C0")) + return Color.LIGHT_GRAY; + else if (color.equals("green") || color.equals("#008000")) + return Color.GREEN; + else if (color.equals("olive") || color.equals("#808000")) + return new Color(128, 128, 0); + else if (color.equals("teal") || color.equals("#008080")) + return new Color(0, 128, 128); + else if (color.equals("blue") || color.equals("#0000FF")) + return Color.BLUE; + else if (color.equals("lime") || color.equals("#00FF00")) + return new Color(0, 255, 0); + else if (color.equals("purple") || color.equals("#800080")) + return new Color(128, 0, 128); + else if (color.equals("white") || color.equals("#FFFFFF")) + return Color.WHITE; + else if (color.equals("fuchsia") || color.equals("#FF00FF")) + return Color.MAGENTA; + else if (color.equals("maroon") || color.equals("#800000")) + return new Color(128, 0, 0); + else if (color.equals("Red") || color.equals("#FF0000")) + return Color.RED; + else if (color.equals("Yellow") || color.equals("#FFFF00")) + return Color.YELLOW; + return null; + } + + /** + * This class carries out some of the duties of CSS formatting. This enables views + * to present the CSS formatting while not knowing how the CSS values are cached. + * + * This object is reponsible for the insets of a View and making sure + * the background is maintained according to the CSS attributes. + * + * @author Lillian Angel (langel@redhat.com) + */ + public static class BoxPainter extends Object implements Serializable + { + + /** + * Attribute set for painter + */ + AttributeSet as; + + /** + * Package-private constructor. + * + * @param as - AttributeSet for painter + */ + BoxPainter(AttributeSet as) + { + this.as = as; + } + + /** + * Gets the inset needed on a given side to account for the margin, border + * and padding. + * + * @param size - the size of the box to get the inset for. View.TOP, View.LEFT, + * View.BOTTOM or View.RIGHT. + * @param v - the view making the request. This is used to get the AttributeSet, + * amd may be used to resolve percentage arguments. + * @return the inset + * @throws IllegalArgumentException - for an invalid direction. + */ + public float getInset(int size, View v) + { + // FIXME: Not implemented. + return 0; + } + + /** + * Paints the CSS box according to the attributes given. This should + * paint the border, padding and background. + * + * @param g - the graphics configuration + * @param x - the x coordinate + * @param y - the y coordinate + * @param w - the width of the allocated area + * @param h - the height of the allocated area + * @param v - the view making the request + */ + public void paint(Graphics g, float x, float y, float w, float h, View v) + { + // FIXME: Not implemented. + } + } + + /** + * This class carries out some of the CSS list formatting duties. Implementations + * of this class enable views to present the CSS formatting while not knowing anything + * about how the CSS values are being cached. + * + * @author Lillian Angel (langel@redhat.com) + */ + public static class ListPainter extends Object implements Serializable + { + + /** + * Attribute set for painter + */ + AttributeSet as; + + /** + * Package-private constructor. + * + * @param as - AttributeSet for painter + */ + ListPainter(AttributeSet as) + { + this.as = as; + } + + /** + * Paints the CSS list decoration according to the attributes given. + * + * @param g - the graphics configuration + * @param x - the x coordinate + * @param y - the y coordinate + * @param w - the width of the allocated area + * @param h - the height of the allocated area + * @param v - the view making the request + * @param item - the list item to be painted >=0. + */ + public void paint(Graphics g, float x, float y, float w, float h, View v, + int item) + { + // FIXME: Not implemented. + } + } + + /** + * The parser callback for the CSSParser. + */ + class CssParser implements CSSParser.CSSParserCallback + { + /** + * A vector of all the selectors. + * Each element is an array of all the selector tokens + * in a single rule. + */ + Vector selectors; + + /** A vector of all the selector tokens in a rule. */ + Vector selectorTokens; + + /** Name of the current property. */ + String propertyName; + + /** The set of CSS declarations */ + MutableAttributeSet declaration; + + /** + * True if parsing a declaration, that is the Reader will not + * contain a selector. + */ + boolean parsingDeclaration; + + /** True if the attributes are coming from a linked/imported style. */ + boolean isLink; + + /** The base URL */ + URL base; + + /** The parser */ + CSSParser parser; + + /** + * Constructor + */ + CssParser() + { + selectors = new Vector(); + selectorTokens = new Vector(); + parser = new CSSParser(); + base = StyleSheet.this.base; + declaration = new SimpleAttributeSet(); + } + + /** + * Parses the passed in CSS declaration into an AttributeSet. + * + * @param s - the declaration + * @return the set of attributes containing the property and value. + */ + public AttributeSet parseDeclaration(String s) + { + try + { + return parseDeclaration(new StringReader(s)); + } + catch (IOException e) + { + // Do nothing here. + } + return null; + } + + /** + * Parses the passed in CSS declaration into an AttributeSet. + * + * @param r - the reader + * @return the attribute set + * @throws IOException from the reader + */ + public AttributeSet parseDeclaration(Reader r) throws IOException + { + parse(base, r, true, false); + return declaration; + } + + /** + * Parse the given CSS stream + * + * @param base - the url + * @param r - the reader + * @param parseDec - True if parsing a declaration + * @param isLink - True if parsing a link + */ + public void parse(URL base, Reader r, boolean parseDec, boolean isLink) throws IOException + { + parsingDeclaration = parseDec; + this.isLink = isLink; + this.base = base; + + // flush out all storage + propertyName = null; + selectors.clear(); + selectorTokens.clear(); + declaration.removeAttributes(declaration); + + parser.parse(r, this, parseDec); + } + + /** + * Invoked when a valid @import is encountered, + * will call importStyleSheet if a MalformedURLException + * is not thrown in creating the URL. + * + * @param s - the string after @import + */ + public void handleImport(String s) + { + if (s != null) + { + try + { + if (s.startsWith("url(") && s.endsWith(")")) + s = s.substring(4, s.length() - 1); + if (s.indexOf("\"") >= 0) + s = s.replaceAll("\"",""); + + URL url = new URL(s); + if (url == null && base != null) + url = new URL(base, s); + + importStyleSheet(url); + } + catch (MalformedURLException e) + { + // Do nothing here. + } + } + } + + /** + * A selector has been encountered. + * + * @param s - a selector (e.g. P or UL or even P,) + */ + public void handleSelector(String s) + { + if (s.endsWith(",")) + s = s.substring(0, s.length() - 1); + + selectorTokens.addElement(s); + addSelector(); + } + + /** + * Invoked when the start of a rule is encountered. + */ + public void startRule() + { + addSelector(); + } + + /** + * Invoked when a property name is encountered. + * + * @param s - the property + */ + public void handleProperty(String s) + { + propertyName = s; + } + + /** + * Invoked when a property value is encountered. + * + * @param s - the value + */ + public void handleValue(String s) + { + // call addCSSAttribute + // FIXME: Not implemented + } + + /** + * Invoked when the end of a rule is encountered. + */ + public void endRule() + { + // FIXME: Not implemented + // add rules + propertyName = null; + } + + /** + * Adds the selector to the vector. + */ + private void addSelector() + { + int length = selectorTokens.size(); + if (length > 0) + { + Object[] sel = new Object[length]; + System.arraycopy(selectorTokens.toArray(), 0, sel, 0, length); + selectors.add(sel); + selectorTokens.clear(); + } + } + } +} diff --git a/libjava/classpath/javax/swing/text/html/default.css b/libjava/classpath/javax/swing/text/html/default.css new file mode 100644 index 00000000000..f2a44f8c8bf --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/default.css @@ -0,0 +1,378 @@ +/* default.css -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +nobr { + white-space: nowrap; +} + +ol { + margin-right: 50px; + margin-top: 10px; + margin-left: 50px; + margin-bottom: 10px; + list-style-type: decimal; +} + +u { + text-decoration: underline; +} + +s { + text-decoration: line-through; +} + +p { + margin-top: 15px; +} + +dd p { + margin-left: 0px; + margin-top: 0px; + margin-bottom: 0px; +} + +ol li p { + margin-top: 0px; + margin-bottom: 0px; +} + + +address { + font-style: italic; + color: blue; +} + +i { + font-style: italic; +} + +h6 { + margin-top: 10px; + font-size: xx-small; + font-weight: bold; + margin-bottom: 10px; +} + +h5 { + margin-top: 10px; + font-size: x-small; + font-weight: bold; + margin-bottom: 10px; +} + +h4 { + margin-top: 10px; + font-size: small; + font-weight: bold; + margin-bottom: 10px; +} + +h3 { + margin-top: 10px; + font-size: medium; + font-weight: bold; + margin-bottom: 10px; +} + +dir li p { + margin-top: 0px; + margin-bottom: 0px; +} + +h2 { + margin-top: 10px; + font-size: large; + font-weight: bold; + margin-bottom: 10px; +} + +b { + font-weight: bold; +} + +h1 { + margin-top: 10px; + font-size: x-large; + font-weight: bold; + margin-bottom: 10px; +} + +caption { + text-align: center; + caption-side: top; +} + +a { + text-decoration: underline; + color: blue; +} + +ul li ul li ul li { + margin-left: 0px; + margin-top: 0px; + margin-bottom: 0px; +} + +menu { + margin-right: 40px; + margin-top: 10px; + margin-left: 40px; + margin-bottom: 10px; +} + +menu li p { + margin-top: 0px; + margin-bottom: 0px; +} + +sup { + vertical-align: super; +} + +body { + margin-right: 0px; + margin-left: 0px; + font-family: Serif; + font-size: 14pt; + font-weight: normal; + color: black; +} + +ul li ul li ul { + margin-right: 25px; + margin-left: 25px; + list-style-type: square; +} + +blockquote { + margin-right: 35px; + margin-left: 35px; + margin-top: 5px; + margin-bottom: 5px; +} + +samp { + font-family: Monospaced; + font-size: small; +} + +cite { + font-style: italic; +} + +sub { + vertical-align: sub; +} + +em { + font-style: italic; +} + +ul li p { + margin-top: 0px; + margin-bottom: 0px; +} + +ul li ul li { + margin-right: 0px; + margin-left: 0px; + margin-top: 0px; + margin-bottom: 0px; +} + +var { + font-style: italic; + font-weight: bold; +} + +table { + border-color: Gray; + border-style: outset; +} + +dfn { + font-style: italic; +} + +menu li { + margin-right: 0px; + margin-left: 0px; + margin-top: 0px; + margin-bottom: 0px; +} + +strong { + font-weight: bold; +} + +ul { + margin-right: 50px; + margin-top: 10px; + margin-left: 50px; + margin-bottom: 10px; + list-style-type: disc; +} + +center { + text-align: center; +} + +ul li ul { + margin-right: 25px; + margin-left: 25px; + list-style-type: circle; +} + +kbd { + font-family: Monospaced; + font-size: small; +} + +dir li { + margin-right: 0px; + margin-left: 0px; + margin-top: 0px; + margin-bottom: 0px; +} + +ul li menu { + margin-right: 25px; + margin-left: 25px; + list-style-type: circle; +} + +dt { + margin-top: 0px; + margin-bottom: 0px; +} + +ol li { + margin-right: 0px; + margin-left: 0px; + margin-top: 0px; + margin-bottom: 0px; +} + +li p { + margin-top: 0px; + margin-bottom: 0px; +} + +default { +} + +strike { + text-decoration: line-through; +} + +dl { + margin-left: 0px; + margin-top: 10px; + margin-bottom: 10px; +} + +tt { + font-family: Monospaced; +} + +ul li { + margin-right: 0px; + margin-left: 0px; + margin-top: 0px; + margin-bottom: 0px; +} + +dir { + margin-right: 40px; + margin-top: 10px; + margin-left: 40px; + margin-bottom: 10px; +} + +tr { + text-align: left; +} + +pre p { + margin-top: 0px; +} + +dd { + margin-right: 40px; + margin-top: 0px; + margin-left: 40px; + margin-bottom: 0px; +} + +th { + padding-bottom: 3px; + text-align: center; + padding-top: 3px; + padding-right: 3px; + padding-left: 3px; + font-weight: bold; + border-color: Gray; + border-style: inset; +} + +pre { + margin-top: 5px; + font-family: Monospaced; + margin-bottom: 5px; +} + +td { + padding-bottom: 3px; + padding-top: 3px; + padding-right: 3px; + padding-left: 3px; + border-color: Gray; + border-style: inset; +} + +code { + font-family: Monospaced; + font-size: small; +} + +small { + font-size: x-small; +} + +big { + font-size: x-large; +} |