summaryrefslogtreecommitdiff
path: root/libjava/classpath/javax/swing/text
diff options
context:
space:
mode:
authortromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>2005-09-23 19:36:46 +0000
committertromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>2005-09-23 19:36:46 +0000
commit49792907376493f0939563eb0219b96a48f1ae3b (patch)
treeb2c2abf473309eac532cafbad81b20f3270ff45f /libjava/classpath/javax/swing/text
parent68cf394a99ed232a528346d711e946d4c9a902b5 (diff)
downloadgcc-49792907376493f0939563eb0219b96a48f1ae3b.tar.gz
Initial revision
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@104578 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/classpath/javax/swing/text')
-rw-r--r--libjava/classpath/javax/swing/text/AbstractWriter.java480
-rw-r--r--libjava/classpath/javax/swing/text/BoxView.java714
-rw-r--r--libjava/classpath/javax/swing/text/CompositeView.java652
-rw-r--r--libjava/classpath/javax/swing/text/ElementIterator.java181
-rw-r--r--libjava/classpath/javax/swing/text/FlowView.java617
-rw-r--r--libjava/classpath/javax/swing/text/GlyphView.java521
-rw-r--r--libjava/classpath/javax/swing/text/IconView.java128
-rw-r--r--libjava/classpath/javax/swing/text/LabelView.java54
-rw-r--r--libjava/classpath/javax/swing/text/LayoutQueue.java115
-rw-r--r--libjava/classpath/javax/swing/text/ParagraphView.java89
10 files changed, 3551 insertions, 0 deletions
diff --git a/libjava/classpath/javax/swing/text/AbstractWriter.java b/libjava/classpath/javax/swing/text/AbstractWriter.java
new file mode 100644
index 00000000000..d5fc395e1ac
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/AbstractWriter.java
@@ -0,0 +1,480 @@
+/* AbstractWriter.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;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Arrays;
+import java.util.Enumeration;
+
+/**
+ * This is an abstract base class for writing Document instances to a
+ * Writer. A concrete subclass must implement a method to iterate
+ * over the Elements of the Document and correctly format them.
+ */
+public abstract class AbstractWriter
+{
+ /**
+ * The default line separator character.
+ * @specnote although this is a constant, it is not static in the JDK
+ */
+ protected static final char NEWLINE = '\n';
+
+ // Where we write.
+ private Writer writer;
+ // How we iterate over the document.
+ private ElementIterator iter;
+ // The document over which we iterate.
+ private Document document;
+ // Maximum number of characters per line.
+ private int maxLineLength = 100;
+ // Number of characters we have currently written.
+ private int lineLength;
+ // True if we can apply line wrapping.
+ private boolean canWrapLines; // FIXME default?
+ // The number of spaces per indentation level.
+ private int indentSpace = 2;
+ // The current indentation level.
+ private int indentLevel;
+ // True if we have indented this line.
+ private boolean indented;
+ // Starting offset in document.
+ private int startOffset;
+ // Ending offset in document.
+ private int endOffset;
+ // The line separator string.
+ private String lineSeparator = "" + NEWLINE;
+ // The characters making up the line separator.
+ private char[] lineSeparatorChars = lineSeparator.toCharArray();
+
+ /**
+ * Create a new AbstractWriter with the indicated Writer and
+ * Document. The full range of the Document will be used. The
+ * internal ElementIterator will be initialized with the Document's
+ * root node.
+ */
+ protected AbstractWriter(Writer writer, Document doc)
+ {
+ this.writer = writer;
+ this.iter = new ElementIterator(doc);
+ this.document = doc;
+ this.startOffset = 0;
+ this.endOffset = doc.getLength();
+ }
+
+ /**
+ * Create a new AbstractWriter with the indicated Writer and
+ * Document. The full range of the Document will be used. The
+ * internal ElementIterator will be initialized with the Document's
+ * root node.
+ */
+ protected AbstractWriter(Writer writer, Document doc, int pos, int len)
+ {
+ this.writer = writer;
+ this.iter = new ElementIterator(doc);
+ this.document = doc;
+ this.startOffset = pos;
+ this.endOffset = pos + len;
+ }
+
+ /**
+ * Create a new AbstractWriter with the indicated Writer and
+ * Element. The full range of the Element will be used.
+ */
+ protected AbstractWriter(Writer writer, Element elt)
+ {
+ this.writer = writer;
+ this.iter = new ElementIterator(elt);
+ this.document = elt.getDocument();
+ this.startOffset = elt.getStartOffset();
+ this.endOffset = elt.getEndOffset();
+ }
+
+ /**
+ * Create a new AbstractWriter with the indicated Writer and
+ * Element. The full range of the Element will be used. The range
+ * will be limited to the indicated range of the Document.
+ */
+ protected AbstractWriter(Writer writer, Element elt, int pos, int len)
+ {
+ this.writer = writer;
+ this.iter = new ElementIterator(elt);
+ this.document = elt.getDocument();
+ this.startOffset = pos;
+ this.endOffset = pos + len;
+ }
+
+ /**
+ * Return the ElementIterator for this writer.
+ */
+ protected ElementIterator getElementIterator()
+ {
+ return iter;
+ }
+
+ /**
+ * Return the Writer to which we are writing.
+ * @since 1.3
+ */
+ protected Writer getWriter()
+ {
+ return writer;
+ }
+
+ /**
+ * Return this writer's Document.
+ */
+ protected Document getDocument()
+ {
+ return document;
+ }
+
+ /**
+ * This method must be overridden by a concrete subclass. It is
+ * responsible for iterating over the Elements of the Document and
+ * writing them out.
+ */
+ protected abstract void write() throws IOException, BadLocationException;
+
+ /**
+ * Return the text of the Document that is associated with the given
+ * Element. If the Element is not a leaf Element, this will throw
+ * BadLocationException.
+ *
+ * @throws BadLocationException if the element is not a leaf
+ */
+ protected String getText(Element elt) throws BadLocationException
+ {
+ if (! elt.isLeaf())
+ throw new BadLocationException("Element is not a leaf",
+ elt.getStartOffset());
+ return document.getText(elt.getStartOffset(), elt.getEndOffset());
+ }
+
+ /**
+ * This method calls Writer.write on the indicated data, and updates
+ * the current line length. This method does not look for newlines
+ * in the written data; the caller is responsible for that.
+ *
+ * @since 1.3
+ */
+ protected void output(char[] data, int start, int len) throws IOException
+ {
+ writer.write(data, start, len);
+ lineLength += len;
+ }
+
+ /**
+ * Write a line separator using the output method, and then reset
+ * the current line length.
+ *
+ * @since 1.3
+ */
+ protected void writeLineSeparator() throws IOException
+ {
+ output(lineSeparatorChars, 0, lineSeparatorChars.length);
+ lineLength = 0;
+ indented = false;
+ }
+
+ /**
+ * Write a single character.
+ */
+ protected void write(char ch) throws IOException
+ {
+ write(new char[] { ch }, 0, 1);
+ }
+
+ /**
+ * Write a String.
+ */
+ protected void write(String s) throws IOException
+ {
+ char[] v = s.toCharArray();
+ write(v, 0, v.length);
+ }
+
+ /**
+ * Write a character array to the output Writer, properly handling
+ * newlines and, if needed, wrapping lines as they are output.
+ * @since 1.3
+ */
+ protected void write(char[] data, int start, int len) throws IOException
+ {
+ if (getCanWrapLines())
+ {
+ // FIXME: should we be handling newlines specially here?
+ for (int i = 0; i < len; )
+ {
+ int start_i = i;
+ // Find next space.
+ while (i < len && data[start + i] != ' ')
+ ++i;
+ if (i < len && lineLength + i - start_i >= maxLineLength)
+ writeLineSeparator();
+ else if (i < len)
+ {
+ // Write the trailing space.
+ ++i;
+ }
+ // Write out the text.
+ output(data, start + start_i, start + i - start_i);
+ }
+ }
+ else
+ {
+ int saved_i = start;
+ for (int i = start; i < start + len; ++i)
+ {
+ if (data[i] == NEWLINE)
+ {
+ output(data, saved_i, i - saved_i);
+ writeLineSeparator();
+ }
+ }
+ if (saved_i < start + len - 1)
+ output(data, saved_i, start + len - saved_i);
+ }
+ }
+
+ /**
+ * Indent this line by emitting spaces, according to the current
+ * indent level and the current number of spaces per indent. After
+ * this method is called, the current line is no longer considered
+ * to be empty, even if no spaces are actually written.
+ */
+ protected void indent() throws IOException
+ {
+ int spaces = indentLevel * indentSpace;
+ if (spaces > 0)
+ {
+ char[] v = new char[spaces];
+ Arrays.fill(v, ' ');
+ write(v, 0, v.length);
+ }
+ indented = true;
+ }
+
+ /**
+ * Return the index of the Document at which output starts.
+ * @since 1.3
+ */
+ public int getStartOffset()
+ {
+ return startOffset;
+ }
+
+ /**
+ * Return the index of the Document at which output ends.
+ * @since 1.3
+ */
+ public int getEndOffset()
+ {
+ return endOffset;
+ }
+
+ /**
+ * Return true if the Element's range overlaps our desired output
+ * range; false otherwise.
+ */
+ protected boolean inRange(Element elt)
+ {
+ int eltStart = elt.getStartOffset();
+ int eltEnd = elt.getEndOffset();
+ return ((eltStart >= startOffset && eltStart < endOffset)
+ || (eltEnd >= startOffset && eltEnd < endOffset));
+ }
+
+ /**
+ * Output the text of the indicated Element, properly clipping it to
+ * the range of the Document specified when the AbstractWriter was
+ * created.
+ */
+ protected void text(Element elt) throws BadLocationException, IOException
+ {
+ int eltStart = elt.getStartOffset();
+ int eltEnd = elt.getEndOffset();
+
+ eltStart = Math.max(eltStart, startOffset);
+ eltEnd = Math.min(eltEnd, endOffset);
+ write(document.getText(eltStart, eltEnd));
+ }
+
+ /**
+ * Set the maximum line length.
+ */
+ protected void setLineLength(int maxLineLength)
+ {
+ this.maxLineLength = maxLineLength;
+ }
+
+ /**
+ * Return the maximum line length.
+ * @since 1.3
+ */
+ protected int getLineLength()
+ {
+ return maxLineLength;
+ }
+
+ /**
+ * Set the current line length.
+ * @since 1.3
+ */
+ protected void setCurrentLineLength(int lineLength)
+ {
+ this.lineLength = lineLength;
+ }
+
+ /**
+ * Return the current line length.
+ * @since 1.3
+ */
+ protected int getCurrentLineLength()
+ {
+ return lineLength;
+ }
+
+ /**
+ * Return true if the line is empty, false otherwise. The line is
+ * empty if nothing has been written since the last newline, and
+ * indent has not been invoked.
+ */
+ protected boolean isLineEmpty()
+ {
+ return lineLength == 0 && ! indented;
+ }
+
+ /**
+ * Set the flag indicating whether lines will wrap. This affects
+ * the behavior of write().
+ * @since 1.3
+ */
+ protected void setCanWrapLines(boolean canWrapLines)
+ {
+ this.canWrapLines = canWrapLines;
+ }
+
+ /**
+ * Return true if lines printed via write() will wrap, false
+ * otherwise.
+ * @since 1.3
+ */
+ protected boolean getCanWrapLines()
+ {
+ return canWrapLines;
+ }
+
+ /**
+ * Set the number of spaces per indent level.
+ * @since 1.3
+ */
+ protected void setIndentSpace(int indentSpace)
+ {
+ this.indentSpace = indentSpace;
+ }
+
+ /**
+ * Return the number of spaces per indent level.
+ * @since 1.3
+ */
+ protected int getIndentSpace()
+ {
+ return indentSpace;
+ }
+
+ /**
+ * Set the current line separator.
+ * @since 1.3
+ */
+ public void setLineSeparator(String lineSeparator)
+ {
+ this.lineSeparator = lineSeparator;
+ this.lineSeparatorChars = lineSeparator.toCharArray();
+ }
+
+ /**
+ * Return the current line separator.
+ * @since 1.3
+ */
+ public String getLineSeparator()
+ {
+ return lineSeparator;
+ }
+
+ /**
+ * Increment the indent level.
+ */
+ protected void incrIndent()
+ {
+ ++indentLevel;
+ }
+
+ /**
+ * Decrement the indent level.
+ */
+ protected void decrIndent()
+ {
+ --indentLevel;
+ }
+
+ /**
+ * Return the current indent level.
+ * @since 1.3
+ */
+ protected int getIndentLevel()
+ {
+ return indentLevel;
+ }
+
+ /**
+ * Print the given AttributeSet as a sequence of assignment-like
+ * strings, e.g. "key=value".
+ */
+ protected void writeAttributes(AttributeSet attrs) throws IOException
+ {
+ Enumeration e = attrs.getAttributeNames();
+ while (e.hasMoreElements())
+ {
+ Object name = e.nextElement();
+ Object val = attrs.getAttribute(name);
+ write(name + "=" + val);
+ writeLineSeparator();
+ }
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/BoxView.java b/libjava/classpath/javax/swing/text/BoxView.java
new file mode 100644
index 00000000000..0f8ba1ce15e
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/BoxView.java
@@ -0,0 +1,714 @@
+/* BoxView.java -- An composite view
+ 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;
+
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+import javax.swing.SizeRequirements;
+
+/**
+ * An implementation of {@link CompositeView} that arranges its children in
+ * a box along one axis. This is comparable to how the <code>BoxLayout</code>
+ * works, but for <code>View</code> children.
+ *
+ * @author Roman Kennke (roman@kennke.org)
+ */
+public class BoxView
+ extends CompositeView
+{
+
+ /**
+ * The axis along which this <code>BoxView</code> is laid out.
+ */
+ int myAxis;
+
+ /**
+ * Indicates wether the layout in X_AXIS is valid.
+ */
+ boolean xLayoutValid;
+
+ /**
+ * Indicates whether the layout in Y_AXIS is valid.
+ */
+ boolean yLayoutValid;
+
+ /**
+ * The spans in X direction of the children.
+ */
+ int[] spansX;
+
+ /**
+ * The spans in Y direction of the children.
+ */
+ int[] spansY;
+
+ /**
+ * The offsets of the children in X direction relative to this BoxView's
+ * inner bounds.
+ */
+ int[] offsetsX;
+
+ /**
+ * The offsets of the children in Y direction relative to this BoxView's
+ * inner bounds.
+ */
+ int[] offsetsY;
+
+ /**
+ * The current width.
+ */
+ int width;
+
+ /**
+ * The current height.
+ */
+ int height;
+
+ /**
+ * Creates a new <code>BoxView</code> for the given
+ * <code>Element</code> and axis. Valid values for the axis are
+ * {@link View#X_AXIS} and {@link View#Y_AXIS}.
+ *
+ * @param element the element that is rendered by this BoxView
+ * @param axis the axis along which the box is laid out
+ */
+ public BoxView(Element element, int axis)
+ {
+ super(element);
+ myAxis = axis;
+ xLayoutValid = false;
+ yLayoutValid = false;
+
+ // Initialize the cache arrays.
+ spansX = new int[0];
+ spansY = new int[0];
+ offsetsX = new int[0];
+ offsetsY = new int[0];
+
+ width = 0;
+ height = 0;
+ }
+
+ /**
+ * Returns the axis along which this <code>BoxView</code> is laid out.
+ *
+ * @return the axis along which this <code>BoxView</code> is laid out
+ */
+ public int getAxis()
+ {
+ return myAxis;
+ }
+
+ /**
+ * Sets the axis along which this <code>BoxView</code> is laid out.
+ *
+ * Valid values for the axis are {@link View#X_AXIS} and
+ * {@link View#Y_AXIS}.
+ *
+ * @param axis the axis along which this <code>BoxView</code> is laid out
+ */
+ public void setAxis(int axis)
+ {
+ myAxis = axis;
+ }
+
+ /**
+ * Marks the layout along the specified axis as invalid. This is triggered
+ * automatically when any of the child view changes its preferences
+ * via {@link #preferenceChanged(View, boolean, boolean)}.
+ *
+ * The layout will be updated the next time when {@link #setSize()} is
+ * called, typically from within the {@link #paint()} method.
+ *
+ * Valid values for the axis are {@link View#X_AXIS} and
+ * {@link View#Y_AXIS}.
+ *
+ * @param axis an <code>int</code> value
+ */
+ public void layoutChanged(int axis)
+ {
+ switch (axis)
+ {
+ case X_AXIS:
+ xLayoutValid = false;
+ break;
+ case Y_AXIS:
+ yLayoutValid = false;
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid axis parameter.");
+ }
+ }
+
+ /**
+ * Returns <code>true</code> if the layout along the specified
+ * <code>axis</code> is valid, <code>false</code> otherwise.
+ *
+ * Valid values for the axis are {@link View#X_AXIS} and
+ * {@link View#Y_AXIS}.
+ *
+ * @param axis the axis
+ *
+ * @return <code>true</code> if the layout along the specified
+ * <code>axis</code> is valid, <code>false</code> otherwise
+ */
+ protected boolean isLayoutValid(int axis)
+ {
+ boolean valid = false;
+ switch (axis)
+ {
+ case X_AXIS:
+ valid = xLayoutValid;
+ break;
+ case Y_AXIS:
+ valid = yLayoutValid;
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid axis parameter.");
+ }
+ return valid;
+ }
+
+ /**
+ * Paints the child <code>View</code> at the specified <code>index</code>.
+ * This method modifies the actual values in <code>alloc</code> so make
+ * sure you have a copy of the original values if you need them.
+ *
+ * @param g the <code>Graphics</code> context to paint to
+ * @param alloc the allocated region for the child to paint into
+ * @param index the index of the child to be painted
+ *
+ * @see {@link #childAllocation}
+ */
+ protected void paintChild(Graphics g, Rectangle alloc, int index)
+ {
+ View child = getView(index);
+ childAllocation(index, alloc);
+ child.paint(g, alloc);
+ }
+
+ /**
+ * Replaces child views by some other child views. If there are no views to
+ * remove (<code>length == 0</code>), the result is a simple insert, if
+ * there are no children to add (<code>view == null</code>) the result
+ * is a simple removal.
+ *
+ * In addition this invalidates the layout and resizes the internal cache
+ * for the child allocations. The old children's cached allocations can
+ * still be accessed (although they are not guaranteed to be valid), and
+ * the new children will have an initial offset and span of 0.
+ *
+ * @param offset the start offset from where to remove children
+ * @param length the number of children to remove
+ * @param views the views that replace the removed children
+ */
+ public void replace(int offset, int length, View[] views)
+ {
+ // Resize and copy data for cache arrays.
+ // The spansX cache.
+ int oldSize = getViewCount();
+
+ int[] newSpansX = new int[oldSize - length + views.length];
+ System.arraycopy(spansX, 0, newSpansX, 0, offset);
+ System.arraycopy(spansX, offset + length, newSpansX,
+ offset + views.length,
+ oldSize - (offset + length));
+ spansX = newSpansX;
+
+ // The spansY cache.
+ int[] newSpansY = new int[oldSize - length + views.length];
+ System.arraycopy(spansY, 0, newSpansY, 0, offset);
+ System.arraycopy(spansY, offset + length, newSpansY,
+ offset + views.length,
+ oldSize - (offset + length));
+ spansY = newSpansY;
+
+ // The offsetsX cache.
+ int[] newOffsetsX = new int[oldSize - length + views.length];
+ System.arraycopy(offsetsX, 0, newOffsetsX, 0, offset);
+ System.arraycopy(offsetsX, offset + length, newOffsetsX,
+ offset + views.length,
+ oldSize - (offset + length));
+ offsetsX = newOffsetsX;
+
+ // The offsetsY cache.
+ int[] newOffsetsY = new int[oldSize - length + views.length];
+ System.arraycopy(offsetsY, 0, newOffsetsY, 0, offset);
+ System.arraycopy(offsetsY, offset + length, newOffsetsY,
+ offset + views.length,
+ oldSize - (offset + length));
+ offsetsY = newOffsetsY;
+
+ // Actually perform the replace.
+ super.replace(offset, length, views);
+
+ // Invalidate layout information.
+ layoutChanged(X_AXIS);
+ layoutChanged(Y_AXIS);
+ }
+
+ /**
+ * Renders the <code>Element</code> that is associated with this
+ * <code>View</code>.
+ *
+ * @param g the <code>Graphics</code> context to render to
+ * @param a the allocated region for the <code>Element</code>
+ */
+ public void paint(Graphics g, Shape a)
+ {
+ // Adjust size if the size is changed.
+ Rectangle bounds = a.getBounds();
+
+ if (bounds.width != getWidth() || bounds.height != getHeight())
+ setSize(bounds.width, bounds.height);
+
+ Rectangle inside = getInsideAllocation(a);
+
+ Rectangle copy = new Rectangle(inside);
+ int count = getViewCount();
+ for (int i = 0; i < count; ++i)
+ {
+ // TODO: Figure out if the parameter to paintChild is meant to
+ // be the child allocation or the allocation of this BoxView.
+ // I assume the second option here.
+ // We pass this method a copy of the inside rectangle here because
+ // it modifies the actual values.
+ copy.setBounds(inside);
+ paintChild(g, copy, i);
+ }
+ }
+
+ /**
+ * Returns the preferred span of the content managed by this
+ * <code>View</code> along the specified <code>axis</code>.
+ *
+ * @param axis the axis
+ *
+ * @return the preferred span of this <code>View</code>.
+ */
+ public float getPreferredSpan(int axis)
+ {
+ SizeRequirements sr = new SizeRequirements();
+ int pref = baselineRequirements(axis, sr).preferred;
+ return (float) pref;
+ }
+
+ public float getMaximumSpan(int axis)
+ {
+ if (axis == getAxis())
+ return getPreferredSpan(axis);
+ else
+ return Integer.MAX_VALUE;
+ }
+
+ /**
+ * Calculates the size requirements for this <code>BoxView</code> along
+ * the specified axis.
+ *
+ * @param axis the axis that is examined
+ * @param sr the <code>SizeRequirements</code> object to hold the result,
+ * if <code>null</code>, a new one is created
+ *
+ * @return the size requirements for this <code>BoxView</code> along
+ * the specified axis
+ */
+ protected SizeRequirements baselineRequirements(int axis,
+ SizeRequirements sr)
+ {
+ SizeRequirements result;
+ if (axis == myAxis)
+ result = calculateMajorAxisRequirements(axis, sr);
+ else
+ result = calculateMinorAxisRequirements(axis, sr);
+ return result;
+ }
+
+ /**
+ * Calculates the size requirements of this <code>BoxView</code> along
+ * its major axis, that is the axis specified in the constructor.
+ *
+ * @param axis the axis that is examined
+ * @param sr the <code>SizeRequirements</code> object to hold the result,
+ * if <code>null</code>, a new one is created
+ *
+ * @return the size requirements for this <code>BoxView</code> along
+ * the specified axis
+ */
+ protected SizeRequirements calculateMajorAxisRequirements(int axis,
+ SizeRequirements sr)
+ {
+ if (sr == null)
+ sr = new SizeRequirements();
+ else
+ {
+ sr.maximum = 0;
+ sr.minimum = 0;
+ sr.preferred = 0;
+ sr.alignment = 0.5F;
+ }
+
+ int count = getViewCount();
+
+ // Sum up the sizes of the children along the specified axis.
+ for (int i = 0; i < count; ++i)
+ {
+ View child = getView(i);
+ sr.minimum += child.getMinimumSpan(axis);
+ sr.preferred += child.getPreferredSpan(axis);
+ sr.maximum += child.getMaximumSpan(axis);
+ }
+ return sr;
+ }
+
+ /**
+ * Calculates the size requirements of this <code>BoxView</code> along
+ * its minor axis, that is the axis opposite to the axis specified in the
+ * constructor.
+ *
+ * @param axis the axis that is examined
+ * @param sr the <code>SizeRequirements</code> object to hold the result,
+ * if <code>null</code>, a new one is created
+ *
+ * @return the size requirements for this <code>BoxView</code> along
+ * the specified axis
+ */
+ protected SizeRequirements calculateMinorAxisRequirements(int axis,
+ SizeRequirements sr)
+ {
+ if (sr == null)
+ sr = new SizeRequirements();
+ else
+ {
+ sr.maximum = 0;
+ sr.minimum = 0;
+ sr.preferred = 0;
+ sr.alignment = 0.5F;
+ }
+
+ int count = getViewCount();
+
+ int aboveBaseline = 0;
+ int belowBaseline = 0;
+ int aboveBaselineMin = 0;
+ int belowBaselineMin = 0;
+ int aboveBaselineMax = 0;
+ int belowBaselineMax = 0;
+
+ for (int i = 0; i < count; ++i)
+ {
+ View child = getView(i);
+ float align = child.getAlignment(axis);
+ int pref = (int) child.getPreferredSpan(axis);
+ int min = (int) child.getMinimumSpan(axis);
+ int max = (int) child.getMaximumSpan(axis);
+ aboveBaseline += (int) (align * pref);
+ belowBaseline += (int) ((1.F - align) * pref);
+ aboveBaselineMin += (int) (align * min);
+ belowBaselineMin += (int) ((1.F - align) * min);
+ aboveBaselineMax += (int) (align * max);
+ belowBaselineMax += (int) ((1.F - align) * max);
+ }
+ sr.minimum = aboveBaselineMin + belowBaselineMin;
+ sr.maximum = aboveBaselineMax + belowBaselineMax;
+ sr.preferred = aboveBaseline + belowBaseline;
+ if (aboveBaseline == 0)
+ sr.alignment = 1.0F;
+ else
+ sr.alignment = (float) (sr.preferred / aboveBaseline);
+
+ return sr;
+ }
+
+ /**
+ * Returns <code>true</code> if the specified point lies before the
+ * given <code>Rectangle</code>, <code>false</code> otherwise.
+ *
+ * &quot;Before&quot; is typically defined as being to the left or above.
+ *
+ * @param x the X coordinate of the point
+ * @param y the Y coordinate of the point
+ * @param r the rectangle to test the point against
+ *
+ * @return <code>true</code> if the specified point lies before the
+ * given <code>Rectangle</code>, <code>false</code> otherwise
+ */
+ protected boolean isBefore(int x, int y, Rectangle r)
+ {
+ boolean result = false;
+
+ if (myAxis == X_AXIS)
+ result = x < r.x;
+ else
+ result = y < r.y;
+
+ return result;
+ }
+
+ /**
+ * Returns <code>true</code> if the specified point lies after the
+ * given <code>Rectangle</code>, <code>false</code> otherwise.
+ *
+ * &quot;After&quot; is typically defined as being to the right or below.
+ *
+ * @param x the X coordinate of the point
+ * @param y the Y coordinate of the point
+ * @param r the rectangle to test the point against
+ *
+ * @return <code>true</code> if the specified point lies after the
+ * given <code>Rectangle</code>, <code>false</code> otherwise
+ */
+ protected boolean isAfter(int x, int y, Rectangle r)
+ {
+ boolean result = false;
+
+ if (myAxis == X_AXIS)
+ result = x > r.x;
+ else
+ result = y > r.y;
+
+ return result;
+ }
+
+ /**
+ * Returns the child <code>View</code> at the specified location.
+ *
+ * @param x the X coordinate
+ * @param y the Y coordinate
+ * @param r the inner allocation of this <code>BoxView</code> on entry,
+ * the allocation of the found child on exit
+ *
+ * @return the child <code>View</code> at the specified location
+ */
+ protected View getViewAtPoint(int x, int y, Rectangle r)
+ {
+ View result = null;
+
+ int count = getViewCount();
+ Rectangle copy = new Rectangle(r);
+
+ for (int i = 0; i < count; ++i)
+ {
+ copy.setBounds(r);
+ childAllocation(i, r);
+ if (copy.contains(x, y))
+ {
+ result = getView(i);
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Computes the allocation for a child <code>View</code>. The parameter
+ * <code>a</code> stores the allocation of this <code>CompositeView</code>
+ * and is then adjusted to hold the allocation of the child view.
+ *
+ * @param index the index of the child <code>View</code>
+ * @param a the allocation of this <code>CompositeView</code> before the
+ * call, the allocation of the child on exit
+ */
+ protected void childAllocation(int index, Rectangle a)
+ {
+ if (! isAllocationValid())
+ layout(a.width, a.height);
+
+ a.x += offsetsX[index];
+ a.y += offsetsY[index];
+ a.width = spansX[index];
+ a.height = spansY[index];
+ }
+
+ /**
+ * Lays out the children of this <code>BoxView</code> with the specified
+ * bounds.
+ *
+ * @param width the width of the allocated region for the children (that
+ * is the inner allocation of this <code>BoxView</code>
+ * @param height the height of the allocated region for the children (that
+ * is the inner allocation of this <code>BoxView</code>
+ */
+ protected void layout(int width, int height)
+ {
+ this.width = width;
+ this.height = height;
+
+ if (myAxis == X_AXIS)
+ {
+ layoutMajorAxis(width, X_AXIS, offsetsX, spansX);
+ layoutMinorAxis(height, Y_AXIS, offsetsY, spansY);
+ }
+ else
+ {
+ layoutMajorAxis(height, Y_AXIS, offsetsY, spansY);
+ layoutMinorAxis(width, X_AXIS, offsetsX, spansX);
+ }
+ }
+
+ /**
+ * Performs the layout along the major axis of a <code>BoxView</code>.
+ *
+ * @param targetSpan the (inner) span of the <code>BoxView</code> in which
+ * to layout the children
+ * @param axis the axis along which the layout is performed
+ * @param offsets the array that holds the offsets of the children on exit
+ * @param offsets the array that holds the spans of the children on exit
+ */
+ protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
+ int[] spans)
+ {
+ // Allocate SizeRequirements for each child view.
+ int count = getViewCount();
+ SizeRequirements[] childReqs = new SizeRequirements[count];
+ for (int i = 0; i < count; ++i)
+ {
+ View view = getView(i);
+ childReqs[i] = new SizeRequirements((int) view.getMinimumSpan(axis),
+ (int) view.getPreferredSpan(axis),
+ (int) view.getMaximumSpan(axis),
+ view.getAlignment(axis));
+ }
+
+ // Calculate the spans and offsets using the SizeRequirements uility
+ // methods.
+ SizeRequirements.calculateTiledPositions(targetSpan, null, childReqs,
+ offsets, spans);
+
+ validateLayout(axis);
+ }
+
+ /**
+ * Performs the layout along the minor axis of a <code>BoxView</code>.
+ *
+ * @param targetSpan the (inner) span of the <code>BoxView</code> in which
+ * to layout the children
+ * @param axis the axis along which the layout is performed
+ * @param offsets the array that holds the offsets of the children on exit
+ * @param offsets the array that holds the spans of the children on exit
+ */
+ protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
+ int[] spans)
+ {
+ // Allocate SizeRequirements for each child view.
+ int count = getViewCount();
+ SizeRequirements[] childReqs = new SizeRequirements[count];
+ for (int i = 0; i < count; ++i)
+ {
+ View view = getView(i);
+ childReqs[i] = new SizeRequirements((int) view.getMinimumSpan(axis),
+ (int) view.getPreferredSpan(axis),
+ (int) view.getMaximumSpan(axis),
+ view.getAlignment(axis));
+ }
+
+ // Calculate the spans and offsets using the SizeRequirements uility
+ // methods.
+ SizeRequirements.calculateAlignedPositions(targetSpan, null, childReqs,
+ offsets, spans);
+ validateLayout(axis);
+ }
+
+ /**
+ * Returns <code>true</code> if the cached allocations for the children
+ * are still valid, <code>false</code> otherwise.
+ *
+ * @return <code>true</code> if the cached allocations for the children
+ * are still valid, <code>false</code> otherwise
+ */
+ protected boolean isAllocationValid()
+ {
+ return isLayoutValid(X_AXIS) && isLayoutValid(Y_AXIS);
+ }
+
+ /**
+ * Return the current width of the box. This is the last allocated width.
+ *
+ * @return the current width of the box
+ */
+ public int getWidth()
+ {
+ return width;
+ }
+
+ /**
+ * Return the current height of the box. This is the last allocated height.
+ *
+ * @return the current height of the box
+ */
+ public int getHeight()
+ {
+ return height;
+ }
+
+ /**
+ * Sets the size of the view. If the actual size has changed, the layout
+ * is updated accordingly.
+ *
+ * @param width the new width
+ * @param height the new height
+ */
+ public void setSize(float width, float height)
+ {
+ if (this.width != (int) width)
+ layoutChanged(X_AXIS);
+ if (this.height != (int) height)
+ layoutChanged(Y_AXIS);
+
+ Rectangle outside = new Rectangle(0, 0, this.width, this.height);
+ Rectangle inside = getInsideAllocation(outside);
+ if (!isAllocationValid())
+ layout(inside.width, inside.height);
+ }
+
+ /**
+ * Sets the layout to valid for a specific axis.
+ *
+ * @param axis the axis for which to validate the layout
+ */
+ void validateLayout(int axis)
+ {
+ if (axis == X_AXIS)
+ xLayoutValid = true;
+ if (axis == Y_AXIS)
+ yLayoutValid = true;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/CompositeView.java b/libjava/classpath/javax/swing/text/CompositeView.java
new file mode 100644
index 00000000000..6776c95727a
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/CompositeView.java
@@ -0,0 +1,652 @@
+/* CompositeView.java -- An abstract view that manages child views
+ 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;
+
+import java.awt.Insets;
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+import javax.swing.SwingConstants;
+
+/**
+ * An abstract base implementation of {@link View} that manages child
+ * <code>View</code>s.
+ *
+ * @author Roman Kennke (roman@kennke.org)
+ */
+public abstract class CompositeView
+ extends View
+{
+
+ /**
+ * The child views of this <code>CompositeView</code>.
+ */
+ View[] children;
+
+ /**
+ * The allocation of this <code>View</code> minus its insets. This is
+ * initialized in {@link #getInsideAllocation} and reused and modified in
+ * {@link childAllocation}.
+ */
+ Rectangle insideAllocation;
+
+ /**
+ * The insets of this <code>CompositeView</code>. This is initialized
+ * in {@link #setInsets}.
+ */
+ Insets insets;
+
+ /**
+ * Creates a new <code>CompositeView</code> for the given
+ * <code>Element</code>.
+ *
+ * @param element the element that is rendered by this CompositeView
+ */
+ public CompositeView(Element element)
+ {
+ super(element);
+ children = new View[0];
+ insets = new Insets(0, 0, 0, 0);
+ }
+
+ /**
+ * Loads the child views of this <code>CompositeView</code>. This method
+ * is called from {@link #setParent} to initialize the child views of
+ * this composite view.
+ *
+ * @param f the view factory to use for creating new child views
+ *
+ * @see #setParent
+ */
+ protected void loadChildren(ViewFactory f)
+ {
+ Element el = getElement();
+ int count = el.getElementCount();
+ View[] newChildren = new View[count];
+ for (int i = 0; i < count; ++i)
+ {
+ Element child = el.getElement(i);
+ View view = f.create(child);
+ newChildren[i] = view;
+ }
+ replace(0, getViewCount(), newChildren);
+ }
+
+ /**
+ * Sets the parent of this <code>View</code>.
+ * In addition to setting the parent, this calls {@link #loadChildren}, if
+ * this <code>View</code> does not already have its children initialized.
+ *
+ * @param parent the parent to set
+ */
+ public void setParent(View parent)
+ {
+ super.setParent(parent);
+ if (parent != null && ((children == null) || children.length == 0))
+ loadChildren(getViewFactory());
+ }
+
+ /**
+ * Returns the number of child views.
+ *
+ * @return the number of child views
+ */
+ public int getViewCount()
+ {
+ return children.length;
+ }
+
+ /**
+ * Returns the child view at index <code>n</code>.
+ *
+ * @param n the index of the requested child view
+ *
+ * @return the child view at index <code>n</code>
+ */
+ public View getView(int n)
+ {
+ return children[n];
+ }
+
+ /**
+ * Replaces child views by some other child views. If there are no views to
+ * remove (<code>length == 0</code>), the result is a simple insert, if
+ * there are no children to add (<code>view == null</code>) the result
+ * is a simple removal.
+ *
+ * @param offset the start offset from where to remove children
+ * @param length the number of children to remove
+ * @param views the views that replace the removed children
+ */
+ public void replace(int offset, int length, View[] views)
+ {
+ // Check for null views to add.
+ for (int i = 0; i < views.length; ++i)
+ if (views[i] == null)
+ throw new NullPointerException("Added views must not be null");
+
+ int endOffset = offset + length;
+
+ // First we set the parent of the removed children to null.
+ for (int i = offset; i < endOffset; ++i)
+ children[i].setParent(null);
+
+ View[] newChildren = new View[children.length - length + views.length];
+ System.arraycopy(children, 0, newChildren, 0, offset);
+ System.arraycopy(views, 0, newChildren, offset, views.length);
+ System.arraycopy(children, offset + length, newChildren,
+ offset + views.length,
+ children.length - (offset + length));
+ children = newChildren;
+
+ // Finally we set the parent of the added children to this.
+ for (int i = 0; i < views.length; ++i)
+ views[i].setParent(this);
+ }
+
+ /**
+ * Returns the allocation for the specified child <code>View</code>.
+ *
+ * @param index the index of the child view
+ * @param a the allocation for this view
+ *
+ * @return the allocation for the specified child <code>View</code>
+ */
+ public Shape getChildAllocation(int index, Shape a)
+ {
+ Rectangle r = getInsideAllocation(a);
+ childAllocation(index, r);
+ return r;
+ }
+
+ /**
+ * Maps a position in the document into the coordinate space of the View.
+ * The output rectangle usually reflects the font height but has a width
+ * of zero.
+ *
+ * @param pos the position of the character in the model
+ * @param a the area that is occupied by the view
+ * @param bias either {@link Position.Bias#Forward} or
+ * {@link Position.Bias#Backward} depending on the preferred
+ * direction bias. If <code>null</code> this defaults to
+ * <code>Position.Bias.Forward</code>
+ *
+ * @return a rectangle that gives the location of the document position
+ * inside the view coordinate space
+ *
+ * @throws BadLocationException if <code>pos</code> is invalid
+ * @throws IllegalArgumentException if b is not one of the above listed
+ * valid values
+ */
+ public Shape modelToView(int pos, Shape a, Position.Bias bias)
+ throws BadLocationException
+ {
+ int childIndex = getViewIndex(pos, bias);
+ if (childIndex != -1)
+ {
+ View child = getView(childIndex);
+ Shape result = child.modelToView(pos, a, bias);
+ if (result == null)
+ throw new AssertionError("" + child.getClass().getName()
+ + ".modelToView() must not return null");
+ return result;
+ }
+ else
+ {
+ // FIXME: Handle the case when we have no child view for the given
+ // position.
+ throw new AssertionError("No child views found where child views are "
+ + "expected. pos = " + pos + ", bias = "
+ + bias);
+ }
+ }
+
+ /**
+ * Maps a region in the document into the coordinate space of the View.
+ *
+ * @param p1 the beginning position inside the document
+ * @param b1 the direction bias for the beginning position
+ * @param p2 the end position inside the document
+ * @param b2 the direction bias for the end position
+ * @param a the area that is occupied by the view
+ *
+ * @return a rectangle that gives the span of the document region
+ * inside the view coordinate space
+ *
+ * @throws BadLocationException if <code>p1</code> or <code>p2</code> are
+ * invalid
+ * @throws IllegalArgumentException if b1 or b2 is not one of the above
+ * listed valid values
+ */
+ public Shape modelToView(int p1, Position.Bias b1,
+ int p2, Position.Bias b2, Shape a)
+ throws BadLocationException
+ {
+ // TODO: This is most likely not 100% ok, figure out what else is to
+ // do here.
+ return super.modelToView(p1, b1, p2, b2, a);
+ }
+
+ /**
+ * Maps coordinates from the <code>View</code>'s space into a position
+ * in the document model.
+ *
+ * @param x the x coordinate in the view space
+ * @param y the y coordinate in the view space
+ * @param a the allocation of this <code>View</code>
+ * @param b the bias to use
+ *
+ * @return the position in the document that corresponds to the screen
+ * coordinates <code>x, y</code>
+ */
+ public int viewToModel(float x, float y, Shape a, Position.Bias[] b)
+ {
+ Rectangle r = getInsideAllocation(a);
+ View view = getViewAtPoint((int) x, (int) y, r);
+ return view.viewToModel(x, y, a, b);
+ }
+
+ /**
+ * Returns the next model location that is visible in eiter north / south
+ * direction or east / west direction. This is used to determine the
+ * placement of the caret when navigating around the document with
+ * the arrow keys.
+ *
+ * This is a convenience method for
+ * {@link #getNextNorthSouthVisualPositionFrom} and
+ * {@link #getNextEastWestVisualPositionFrom}.
+ *
+ * @param pos the model position to start search from
+ * @param b the bias for <code>pos</code>
+ * @param a the allocated region for this view
+ * @param direction the direction from the current position, can be one of
+ * the following:
+ * <ul>
+ * <li>{@link SwingConstants#WEST}</li>
+ * <li>{@link SwingConstants#EAST}</li>
+ * <li>{@link SwingConstants#NORTH}</li>
+ * <li>{@link SwingConstants#SOUTH}</li>
+ * </ul>
+ * @param biasRet the bias of the return value gets stored here
+ *
+ * @return the position inside the model that represents the next visual
+ * location
+ *
+ * @throws BadLocationException if <code>pos</code> is not a valid location
+ * inside the document model
+ * @throws IllegalArgumentException if <code>direction</code> is invalid
+ */
+ public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a,
+ int direction, Position.Bias[] biasRet)
+ {
+ int retVal = -1;
+ switch (direction)
+ {
+ case SwingConstants.WEST:
+ case SwingConstants.EAST:
+ retVal = getNextEastWestVisualPositionFrom(pos, b, a, direction,
+ biasRet);
+ break;
+ case SwingConstants.NORTH:
+ case SwingConstants.SOUTH:
+ retVal = getNextNorthSouthVisualPositionFrom(pos, b, a, direction,
+ biasRet);
+ break;
+ default:
+ throw new IllegalArgumentException("Illegal value for direction.");
+ }
+ return retVal;
+ }
+
+ /**
+ * Returns the index of the child view that represents the specified
+ * model location.
+ *
+ * @param pos the model location for which to determine the child view index
+ * @param b the bias to be applied to <code>pos</code>
+ *
+ * @return the index of the child view that represents the specified
+ * model location
+ */
+ public int getViewIndex(int pos, Position.Bias b)
+ {
+ // FIXME: Handle bias somehow.
+ return getViewIndexAtPosition(pos);
+ }
+
+ /**
+ * Returns <code>true</code> if the specified point lies before the
+ * given <code>Rectangle</code>, <code>false</code> otherwise.
+ *
+ * &quot;Before&quot; is typically defined as being to the left or above.
+ *
+ * @param x the X coordinate of the point
+ * @param y the Y coordinate of the point
+ * @param r the rectangle to test the point against
+ *
+ * @return <code>true</code> if the specified point lies before the
+ * given <code>Rectangle</code>, <code>false</code> otherwise
+ */
+ protected abstract boolean isBefore(int x, int y, Rectangle r);
+
+ /**
+ * Returns <code>true</code> if the specified point lies after the
+ * given <code>Rectangle</code>, <code>false</code> otherwise.
+ *
+ * &quot;After&quot; is typically defined as being to the right or below.
+ *
+ * @param x the X coordinate of the point
+ * @param y the Y coordinate of the point
+ * @param r the rectangle to test the point against
+ *
+ * @return <code>true</code> if the specified point lies after the
+ * given <code>Rectangle</code>, <code>false</code> otherwise
+ */
+ protected abstract boolean isAfter(int x, int y, Rectangle r);
+
+ /**
+ * Returns the child <code>View</code> at the specified location.
+ *
+ * @param x the X coordinate
+ * @param y the Y coordinate
+ * @param r the inner allocation of this <code>BoxView</code> on entry,
+ * the allocation of the found child on exit
+ *
+ * @return the child <code>View</code> at the specified location
+ */
+ protected abstract View getViewAtPoint(int x, int y, Rectangle r);
+
+ /**
+ * Computes the allocation for a child <code>View</code>. The parameter
+ * <code>a</code> stores the allocation of this <code>CompositeView</code>
+ * and is then adjusted to hold the allocation of the child view.
+ *
+ * @param index the index of the child <code>View</code>
+ * @param a the allocation of this <code>CompositeView</code> before the
+ * call, the allocation of the child on exit
+ */
+ protected abstract void childAllocation(int index, Rectangle a);
+
+ /**
+ * Returns the child <code>View</code> that contains the given model
+ * position. The given <code>Rectangle</code> gives the parent's allocation
+ * and is changed to the child's allocation on exit.
+ *
+ * @param pos the model position to query the child <code>View</code> for
+ * @param a the parent allocation on entry and the child allocation on exit
+ *
+ * @return the child view at the given model position
+ */
+ protected View getViewAtPosition(int pos, Rectangle a)
+ {
+ int i = getViewIndexAtPosition(pos);
+ View view = children[i];
+ childAllocation(i, a);
+ return view;
+ }
+
+ /**
+ * Returns the index of the child <code>View</code> for the given model
+ * position.
+ *
+ * @param pos the model position for whicht the child <code>View</code> is
+ * queried
+ *
+ * @return the index of the child <code>View</code> for the given model
+ * position
+ */
+ protected int getViewIndexAtPosition(int pos)
+ {
+ // We have one child view allocated for each child element in
+ // loadChildren(), so this should work.
+ Element el = getElement();
+ int index = el.getElementIndex(pos);
+ return index;
+ }
+
+ /**
+ * Returns the allocation that is given to this <code>CompositeView</code>
+ * minus this <code>CompositeView</code>'s insets.
+ *
+ * Also this translates from an immutable allocation to a mutable allocation
+ * that is typically reused and further narrowed, like in
+ * {@link #childAllocation}.
+ *
+ * @param a the allocation given to this <code>CompositeView</code>
+ *
+ * @return the allocation that is given to this <code>CompositeView</code>
+ * minus this <code>CompositeView</code>'s insets or
+ * <code>null</code> if a was <code>null</code>
+ */
+ protected Rectangle getInsideAllocation(Shape a)
+ {
+ if (a == null)
+ return null;
+
+ Rectangle alloc = a.getBounds();
+ // Initialize the inside allocation rectangle. This is done inside
+ // a synchronized block in order to avoid multiple threads creating
+ // this instance simultanously.
+ Rectangle inside;
+ synchronized(this)
+ {
+ inside = insideAllocation;
+ if (inside == null)
+ {
+ inside = new Rectangle();
+ insideAllocation = inside;
+ }
+ }
+ inside.x = alloc.x - insets.left;
+ inside.y = alloc.y - insets.top;
+ inside.width = alloc.width - insets.left - insets.right;
+ inside.height = alloc.height - insets.top - insets.bottom;
+ return inside;
+ }
+
+ /**
+ * Sets the insets defined by attributes in <code>attributes</code>. This
+ * queries the attribute keys {@link StyleConstants#SpaceAbove},
+ * {@link StyleConstants#SpaceBelow}, {@link StyleConstants#LeftIndent} and
+ * {@link StyleConstants#RightIndent} and calls {@link #setInsets} to
+ * actually set the insets on this <code>CompositeView</code>.
+ *
+ * @param attributes the attributes from which to query the insets
+ */
+ protected void setParagraphInsets(AttributeSet attributes)
+ {
+ Float l = (Float) attributes.getAttribute(StyleConstants.LeftIndent);
+ short left = 0;
+ if (l != null)
+ left = l.shortValue();
+ Float r = (Float) attributes.getAttribute(StyleConstants.RightIndent);
+ short right = 0;
+ if (r != null)
+ right = r.shortValue();
+ Float t = (Float) attributes.getAttribute(StyleConstants.SpaceAbove);
+ short top = 0;
+ if (t != null)
+ top = t.shortValue();
+ Float b = (Float) attributes.getAttribute(StyleConstants.SpaceBelow);
+ short bottom = 0;
+ if (b != null)
+ bottom = b.shortValue();
+ setInsets(top, left, bottom, right);
+ }
+
+ /**
+ * Sets the insets of this <code>CompositeView</code>.
+ *
+ * @param top the top inset
+ * @param left the left inset
+ * @param bottom the bottom inset
+ * @param right the right inset
+ */
+ protected void setInsets(short top, short left, short bottom, short right)
+ {
+ insets.top = top;
+ insets.left = left;
+ insets.bottom = bottom;
+ insets.right = right;
+ }
+
+ /**
+ * Returns the left inset of this <code>CompositeView</code>.
+ *
+ * @return the left inset of this <code>CompositeView</code>
+ */
+ protected short getLeftInset()
+ {
+ return (short) insets.left;
+ }
+
+ /**
+ * Returns the right inset of this <code>CompositeView</code>.
+ *
+ * @return the right inset of this <code>CompositeView</code>
+ */
+ protected short getRightInset()
+ {
+ return (short) insets.right;
+ }
+
+ /**
+ * Returns the top inset of this <code>CompositeView</code>.
+ *
+ * @return the top inset of this <code>CompositeView</code>
+ */
+ protected short getTopInset()
+ {
+ return (short) insets.top;
+ }
+
+ /**
+ * Returns the bottom inset of this <code>CompositeView</code>.
+ *
+ * @return the bottom inset of this <code>CompositeView</code>
+ */
+ protected short getBottomInset()
+ {
+ return (short) insets.bottom;
+ }
+
+ /**
+ * Returns the next model location that is visible in north or south
+ * direction.
+ * This is used to determine the
+ * placement of the caret when navigating around the document with
+ * the arrow keys.
+ *
+ * @param pos the model position to start search from
+ * @param b the bias for <code>pos</code>
+ * @param a the allocated region for this view
+ * @param direction the direction from the current position, can be one of
+ * the following:
+ * <ul>
+ * <li>{@link SwingConstants#NORTH}</li>
+ * <li>{@link SwingConstants#SOUTH}</li>
+ * </ul>
+ * @param biasRet the bias of the return value gets stored here
+ *
+ * @return the position inside the model that represents the next visual
+ * location
+ *
+ * @throws BadLocationException if <code>pos</code> is not a valid location
+ * inside the document model
+ * @throws IllegalArgumentException if <code>direction</code> is invalid
+ */
+ protected int getNextNorthSouthVisualPositionFrom(int pos, Position.Bias b,
+ Shape a, int direction,
+ Position.Bias[] biasRet)
+ {
+ // FIXME: Implement this correctly.
+ return pos;
+ }
+
+ /**
+ * Returns the next model location that is visible in east or west
+ * direction.
+ * This is used to determine the
+ * placement of the caret when navigating around the document with
+ * the arrow keys.
+ *
+ * @param pos the model position to start search from
+ * @param b the bias for <code>pos</code>
+ * @param a the allocated region for this view
+ * @param direction the direction from the current position, can be one of
+ * the following:
+ * <ul>
+ * <li>{@link SwingConstants#EAST}</li>
+ * <li>{@link SwingConstants#WEST}</li>
+ * </ul>
+ * @param biasRet the bias of the return value gets stored here
+ *
+ * @return the position inside the model that represents the next visual
+ * location
+ *
+ * @throws BadLocationException if <code>pos</code> is not a valid location
+ * inside the document model
+ * @throws IllegalArgumentException if <code>direction</code> is invalid
+ */
+ protected int getNextEastWestVisualPositionFrom(int pos, Position.Bias b,
+ Shape a, int direction,
+ Position.Bias[] biasRet)
+ {
+ // FIXME: Implement this correctly.
+ return pos;
+ }
+
+ /**
+ * Determines if the next view in horinzontal direction is located to
+ * the east or west of the view at position <code>pos</code>. Usually
+ * the <code>View</code>s are laid out from the east to the west, so
+ * we unconditionally return <code>false</code> here. Subclasses that
+ * support bidirectional text may wish to override this method.
+ *
+ * @param pos the position in the document
+ * @param bias the bias to be applied to <code>pos</code>
+ *
+ * @return <code>true</code> if the next <code>View</code> is located
+ * to the EAST, <code>false</code> otherwise
+ */
+ protected boolean flipEastAndWestAtEnds(int pos, Position.Bias bias)
+ {
+ return false;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/ElementIterator.java b/libjava/classpath/javax/swing/text/ElementIterator.java
new file mode 100644
index 00000000000..a6a5ff618bd
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/ElementIterator.java
@@ -0,0 +1,181 @@
+/* ElementIterator.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;
+
+/**
+ * This class can be used to iterate over the {@link Element} tree of
+ * a {@link Document} or an {@link Element}. This iterator performs
+ * an "in-order" traversal -- first it visits a node, then each of the
+ * node's children in order. No locking is performed during the
+ * iteration; that is up to the caller.
+ */
+public class ElementIterator implements Cloneable
+{
+ // The root element.
+ private Element root;
+ // The current element.
+ private Element currentElement;
+ // The depth to which we have descended in the tree.
+ private int currentDepth;
+
+ // This is at least as big as the current depth, and at index N
+ // contains the index of the child element we're currently
+ // examining.
+ private int[] state;
+
+ // The previous item.
+ private Element previousItem;
+
+ /**
+ * Create a new ElementIterator to iterate over the given document.
+ * @param document the Document over which we iterate
+ */
+ public ElementIterator(Document document)
+ {
+ this.root = document.getDefaultRootElement();
+ this.currentElement = root;
+ this.state = new int[5];
+ }
+
+ /**
+ * Create a new ElementIterator to iterate over the given document.
+ * @param root the Document over which we iterate
+ */
+ public ElementIterator(Element root)
+ {
+ this.root = root;
+ this.currentElement = root;
+ this.state = new int[5];
+ }
+
+ /**
+ * Returns a new ElementIterator which is a clone of this
+ * ElementIterator.
+ */
+ public Object clone()
+ {
+ try
+ {
+ return super.clone();
+ }
+ catch (CloneNotSupportedException _)
+ {
+ // Can't happen.
+ return null;
+ }
+ }
+
+ /**
+ * Returns the current element.
+ */
+ public Element current()
+ {
+ return currentElement;
+ }
+
+ /**
+ * Returns the depth to which we have descended in the tree.
+ */
+ public int depth()
+ {
+ return currentDepth;
+ }
+
+ /**
+ * Returns the first element in the tree.
+ */
+ public Element first()
+ {
+ // Reset the iterator.
+ currentElement = root;
+ currentDepth = 0;
+ previousItem = null;
+ return root;
+ }
+
+ /**
+ * Advance the iterator and return the next element of the tree,
+ * performing an "in-order" traversal.
+ */
+ public Element next()
+ {
+ previousItem = currentElement;
+ if (currentElement == null)
+ return null;
+ if (! currentElement.isLeaf())
+ {
+ ++currentDepth;
+ if (currentDepth > state.length)
+ {
+ int[] newState = new int[state.length * 2];
+ System.arraycopy(state, 0, newState, 0, state.length);
+ state = newState;
+ }
+ state[currentDepth] = 0;
+ currentElement = currentElement.getElement(0);
+ return currentElement;
+ }
+
+ while (currentDepth > 0)
+ {
+ // At a leaf, or done with a non-leaf's children, so go up a
+ // level.
+ --currentDepth;
+ currentElement = currentElement.getParentElement();
+ ++state[currentDepth];
+ if (state[currentDepth] < currentElement.getElementCount())
+ {
+ currentElement = currentElement.getElement(state[currentDepth]);
+ return currentElement;
+ }
+ }
+
+ currentElement = null;
+ return currentElement;
+ }
+
+ /**
+ * Returns the previous item. Does not modify the iterator state.
+ */
+ public Element previous()
+ {
+ if (currentElement == null || currentElement == root)
+ return null;
+ return previousItem;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/FlowView.java b/libjava/classpath/javax/swing/text/FlowView.java
new file mode 100644
index 00000000000..a6ef89efb78
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/FlowView.java
@@ -0,0 +1,617 @@
+/* FlowView.java -- A composite View
+ 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;
+
+import java.awt.Container;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.util.Vector;
+
+import javax.swing.event.DocumentEvent;
+
+/**
+ * A <code>View</code> that can flows it's children into it's layout space.
+ *
+ * The <code>FlowView</code> manages a set of logical views (that are
+ * the children of the {@link #layoutPool} field). These are translated
+ * at layout time into a set of physical views. These are the views that
+ * are managed as the real child views. Each of these child views represents
+ * a row and are laid out within a box using the superclasses behaviour.
+ * The concrete implementation of the rows must be provided by subclasses.
+ *
+ * @author Roman Kennke (roman@kennke.org)
+ */
+public abstract class FlowView extends BoxView
+{
+ /**
+ * A strategy for translating the logical views of a <code>FlowView</code>
+ * into the real views.
+ */
+ public static class FlowStrategy
+ {
+ /**
+ * Creates a new instance of <code>FlowStragegy</code>.
+ */
+ public FlowStrategy()
+ {
+ }
+
+ /**
+ * Receives notification from a <code>FlowView</code> that some content
+ * has been inserted into the document at a location that the
+ * <code>FlowView</code> is responsible for.
+ *
+ * The default implementation simply calls {@link #layout}.
+ *
+ * @param fv the flow view that sends the notification
+ * @param e the document event describing the change
+ * @param alloc the current allocation of the flow view
+ */
+ public void insertUpdate(FlowView fv, DocumentEvent e, Rectangle alloc)
+ {
+ layout(fv);
+ }
+
+ /**
+ * Receives notification from a <code>FlowView</code> that some content
+ * has been removed from the document at a location that the
+ * <code>FlowView</code> is responsible for.
+ *
+ * The default implementation simply calls {@link #layout}.
+ *
+ * @param fv the flow view that sends the notification
+ * @param e the document event describing the change
+ * @param alloc the current allocation of the flow view
+ */
+ public void removeUpdate(FlowView fv, DocumentEvent e, Rectangle alloc)
+ {
+ layout(fv);
+ }
+
+ /**
+ * Receives notification from a <code>FlowView</code> that some attributes
+ * have changed in the document at a location that the
+ * <code>FlowView</code> is responsible for.
+ *
+ * The default implementation simply calls {@link #layout}.
+ *
+ * @param fv the flow view that sends the notification
+ * @param e the document event describing the change
+ * @param alloc the current allocation of the flow view
+ */
+ public void changedUpdate(FlowView fv, DocumentEvent e, Rectangle alloc)
+ {
+ layout(fv);
+ }
+
+ /**
+ * Returns the logical view of the managed <code>FlowView</code>.
+ *
+ * @param fv the flow view for which to return the logical view
+ *
+ * @return the logical view of the managed <code>FlowView</code>
+ */
+ public View getLogicalView(FlowView fv)
+ {
+ return fv.layoutPool;
+ }
+
+ /**
+ * Performs the layout for the whole view. By default this rebuilds
+ * all the physical views from the logical views of the managed FlowView.
+ *
+ * This is called by {@link FlowLayout#layout} to update the layout of
+ * the view.
+ *
+ * @param fv the flow view for which we perform the layout
+ */
+ public void layout(FlowView fv)
+ {
+ fv.removeAll();
+ Element el = fv.getElement();
+
+ int rowStart = el.getStartOffset();
+ int end = el.getEndOffset();
+ int rowIndex = 0;
+ while (rowStart >= 0 && rowStart < end)
+ {
+ View row = fv.createRow();
+ fv.append(row);
+ rowStart = layoutRow(fv, rowIndex, rowStart);
+ rowIndex++;
+ }
+ }
+
+ /**
+ * Lays out one row of the flow view. This is called by {@link #layout}
+ * to fill one row with child views until the available span is exhausted.
+ *
+ * @param fv the flow view for which we perform the layout
+ * @param rowIndex the index of the row
+ * @param pos the start position for the row
+ *
+ * @return the start position of the next row
+ */
+ protected int layoutRow(FlowView fv, int rowIndex, int pos)
+ {
+ int spanLeft = fv.getFlowSpan(rowIndex);
+ if (spanLeft <= 0)
+ return -1;
+
+ int offset = pos;
+ View row = fv.getView(rowIndex);
+ int flowAxis = fv.getFlowAxis();
+
+ while (spanLeft > 0)
+ {
+ View child = createView(fv, offset, spanLeft, rowIndex);
+ if (child == null)
+ break;
+
+ int span = (int) child.getPreferredSpan(flowAxis);
+ if (span > spanLeft)
+ break;
+
+ row.append(child);
+ spanLeft -= span;
+ offset = child.getEndOffset();
+ }
+ return offset;
+ }
+
+ /**
+ * Creates physical views that form the rows of the flow view. This
+ * can be an entire view from the logical view (if it fits within the
+ * available span), a fragment of such a view (if it doesn't fit in the
+ * available span and can be broken down) or <code>null</code> (if it does
+ * not fit in the available span and also cannot be broken down).
+ *
+ * @param fv the flow view
+ * @param startOffset the start offset for the view to be created
+ * @param spanLeft the available span
+ * @param rowIndex the index of the row
+ *
+ * @return a view to fill the row with, or <code>null</code> if there
+ * is no view or view fragment that fits in the available span
+ */
+ protected View createView(FlowView fv, int offset, int spanLeft,
+ int rowIndex)
+ {
+ // Find the logical element for the given offset.
+ View logicalView = getLogicalView(fv);
+
+ int viewIndex = logicalView.getViewIndex(offset, Position.Bias.Forward);
+ View child = logicalView.getView(viewIndex);
+ int flowAxis = fv.getFlowAxis();
+ int span = (int) child.getPreferredSpan(flowAxis);
+
+ if (span <= spanLeft)
+ return child;
+
+ else if (child.getBreakWeight(flowAxis, offset, spanLeft)
+ > BadBreakWeight)
+ // FIXME: What to do with the pos parameter here?
+ return child.breakView(flowAxis, offset, 0, spanLeft);
+ else
+ return null;
+ }
+ }
+
+ /**
+ * This special subclass of <code>View</code> is used to represent
+ * the logical representation of this view. It does not support any
+ * visual representation, this is handled by the physical view implemented
+ * in the <code>FlowView</code>.
+ */
+ class LogicalView extends View
+ {
+ /**
+ * The child views of this logical view.
+ */
+ Vector children;
+
+ /**
+ * Creates a new LogicalView instance.
+ */
+ LogicalView(Element el)
+ {
+ super(el);
+ children = new Vector();
+ }
+
+ /**
+ * Returns the container that holds this view. The logical view returns
+ * the enclosing FlowView's container here.
+ *
+ * @return the container that holds this view
+ */
+ public Container getContainer()
+ {
+ return FlowView.this.getContainer();
+ }
+
+ /**
+ * Returns the number of child views of this logical view.
+ *
+ * @return the number of child views of this logical view
+ */
+ public int getViewCount()
+ {
+ return children.size();
+ }
+
+ /**
+ * Returns the child view at the specified index.
+ *
+ * @param index the index
+ *
+ * @return the child view at the specified index
+ */
+ public View getView(int index)
+ {
+ return (View) children.get(index);
+ }
+
+ /**
+ * Replaces some child views with other child views.
+ *
+ * @param offset the offset at which to replace child views
+ * @param length the number of children to remove
+ * @param views the views to be inserted
+ */
+ public void replace(int offset, int length, View[] views)
+ {
+ if (length > 0)
+ {
+ for (int count = 0; count < length; ++count)
+ children.remove(offset);
+ }
+
+ int endOffset = offset + views.length;
+ for (int i = offset; i < endOffset; ++i)
+ {
+ children.add(i, views[i - offset]);
+ // Set the parent of the child views to the flow view itself so
+ // it has something to resolve.
+ views[i - offset].setParent(FlowView.this);
+ }
+ }
+
+ /**
+ * Returns the index of the child view that contains the specified
+ * position in the document model.
+ *
+ * @param pos the position for which we are searching the child view
+ * @param b the bias
+ *
+ * @return the index of the child view that contains the specified
+ * position in the document model
+ */
+ public int getViewIndex(int pos, Position.Bias b)
+ {
+ return getElement().getElementIndex(pos);
+ }
+
+ /**
+ * Throws an AssertionError because it must never be called. LogicalView
+ * only serves as a holder for child views and has no visual
+ * representation.
+ */
+ public float getPreferredSpan(int axis)
+ {
+ throw new AssertionError("This method must not be called in "
+ + "LogicalView.");
+ }
+
+ /**
+ * Throws an AssertionError because it must never be called. LogicalView
+ * only serves as a holder for child views and has no visual
+ * representation.
+ */
+ public Shape modelToView(int pos, Shape a, Position.Bias b)
+ throws BadLocationException
+ {
+ throw new AssertionError("This method must not be called in "
+ + "LogicalView.");
+ }
+
+ /**
+ * Throws an AssertionError because it must never be called. LogicalView
+ * only serves as a holder for child views and has no visual
+ * representation.
+ */
+ public void paint(Graphics g, Shape s)
+ {
+ throw new AssertionError("This method must not be called in "
+ + "LogicalView.");
+ }
+
+ /**
+ * Throws an AssertionError because it must never be called. LogicalView
+ * only serves as a holder for child views and has no visual
+ * representation.
+ */
+ public int viewToModel(float x, float y, Shape a, Position.Bias[] b)
+ {
+ throw new AssertionError("This method must not be called in "
+ + "LogicalView.");
+ }
+ }
+
+ /**
+ * The shared instance of FlowStrategy.
+ */
+ static final FlowStrategy sharedStrategy = new FlowStrategy();
+
+ /**
+ * The span of the <code>FlowView</code> that should be flowed.
+ */
+ protected int layoutSpan;
+
+ /**
+ * Represents the logical child elements of this view, encapsulated within
+ * one parent view (an instance of a package private <code>LogicalView</code>
+ * class). These will be translated to a set of real views that are then
+ * displayed on screen. This translation is performed by the inner class
+ * {@link FlowStrategy}.
+ */
+ protected View layoutPool;
+
+ /**
+ * The <code>FlowStrategy</code> to use for translating between the
+ * logical and physical view.
+ */
+ protected FlowStrategy strategy;
+
+ /**
+ * Creates a new <code>FlowView</code> for the given
+ * <code>Element</code> and <code>axis</code>.
+ *
+ * @param element the element that is rendered by this FlowView
+ * @param axis the axis along which the view is tiled, either
+ * <code>View.X_AXIS</code> or <code>View.Y_AXIS</code>, the flow
+ * axis is orthogonal to this one
+ */
+ public FlowView(Element element, int axis)
+ {
+ super(element, axis);
+ strategy = sharedStrategy;
+ }
+
+ /**
+ * Returns the axis along which the view should be flowed. This is
+ * orthogonal to the axis along which the boxes are tiled.
+ *
+ * @return the axis along which the view should be flowed
+ */
+ public int getFlowAxis()
+ {
+ int axis = getAxis();
+ int flowAxis;
+
+ if (axis == X_AXIS)
+ flowAxis = Y_AXIS;
+ else
+ flowAxis = X_AXIS;
+
+ return flowAxis;
+
+ }
+
+ /**
+ * Returns the span of the flow for the specified child view. A flow
+ * layout can be shaped by providing different span values for different
+ * child indices. The default implementation returns the entire available
+ * span inside the view.
+ *
+ * @param index the index of the child for which to return the span
+ *
+ * @return the span of the flow for the specified child view
+ */
+ public int getFlowSpan(int index)
+ {
+ return layoutSpan;
+ }
+
+ /**
+ * Returns the location along the flow axis where the flow span starts
+ * given a child view index. The flow can be shaped by providing
+ * different values here.
+ *
+ * @param index the index of the child for which to return the flow location
+ *
+ * @return the location along the flow axis where the flow span starts
+ */
+ public int getFlowStart(int index)
+ {
+ return getLeftInset(); // TODO: Is this correct?
+ }
+
+ /**
+ * Creates a new view that represents a row within a flow.
+ *
+ * @return a view for a new row
+ */
+ protected abstract View createRow();
+
+ /**
+ * Loads the children of this view. The <code>FlowView</code> does not
+ * directly load its children. Instead it creates a logical view
+ * (@{link #layoutPool}) which is filled by the logical child views.
+ * The real children are created at layout time and each represent one
+ * row.
+ *
+ * This method is called by {@link #setParent} in order to initialize
+ * the view.
+ *
+ * @param vf the view factory to use for creating the child views
+ */
+ protected void loadChildren(ViewFactory vf)
+ {
+ if (layoutPool == null)
+ {
+ layoutPool = new LogicalView(getElement());
+
+ Element el = getElement();
+ int count = el.getElementCount();
+ for (int i = 0; i < count; ++i)
+ {
+ Element childEl = el.getElement(i);
+ View childView = vf.create(childEl);
+ layoutPool.append(childView);
+ }
+ }
+ }
+
+ /**
+ * Performs the layout of this view. If the span along the flow axis changed,
+ * this first calls {@link FlowStrategy.layout} in order to rebuild the
+ * rows of this view. Then the superclass's behaviour is called to arrange
+ * the rows within the box.
+ *
+ * @param width the width of the view
+ * @param height the height of the view
+ */
+ protected void layout(int width, int height)
+ {
+ boolean rebuild = false;
+
+ int flowAxis = getFlowAxis();
+ if (flowAxis == X_AXIS)
+ {
+ rebuild = !(width == layoutSpan);
+ layoutSpan = width;
+ }
+ else
+ {
+ rebuild = !(height == layoutSpan);
+ layoutSpan = height;
+ }
+
+ if (rebuild)
+ strategy.layout(this);
+
+ // TODO: If the span along the box axis has changed in the process of
+ // relayouting the rows (that is, if rows have been added or removed),
+ // call preferenceChanged in order to throw away cached layout information
+ // of the surrounding BoxView.
+
+ super.layout(width, height);
+ }
+
+ /**
+ * Receice notification that some content has been inserted in the region
+ * that this view is responsible for. This calls
+ * {@link FlowStrategy#insertUpdate}.
+ *
+ * @param changes the document event describing the changes
+ * @param a the current allocation of the view
+ * @param vf the view factory that is used for creating new child views
+ */
+ public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory vf)
+ {
+ strategy.insertUpdate(this, changes, getInsideAllocation(a));
+ }
+
+ /**
+ * Receice notification that some content has been removed from the region
+ * that this view is responsible for. This calls
+ * {@link FlowStrategy#removeUpdate}.
+ *
+ * @param changes the document event describing the changes
+ * @param a the current allocation of the view
+ * @param vf the view factory that is used for creating new child views
+ */
+ public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory vf)
+ {
+ strategy.removeUpdate(this, changes, getInsideAllocation(a));
+ }
+
+ /**
+ * Receice notification that some attributes changed in the region
+ * that this view is responsible for. This calls
+ * {@link FlowStrategy#changedUpdate}.
+ *
+ * @param changes the document event describing the changes
+ * @param a the current allocation of the view
+ * @param vf the view factory that is used for creating new child views
+ */
+ public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory vf)
+ {
+ strategy.changedUpdate(this, changes, getInsideAllocation(a));
+ }
+
+ /**
+ * Returns the index of the child <code>View</code> for the given model
+ * position.
+ *
+ * This is implemented to iterate over the children of this
+ * view (the rows) and return the index of the first view that contains
+ * the given position.
+ *
+ * @param pos the model position for whicht the child <code>View</code> is
+ * queried
+ *
+ * @return the index of the child <code>View</code> for the given model
+ * position
+ */
+ protected int getViewIndexAtPosition(int pos)
+ {
+ // First make sure we have a valid layout.
+ if (!isAllocationValid())
+ layout(getWidth(), getHeight());
+
+ int count = getViewCount();
+ int result = -1;
+
+ for (int i = 0; i < count; ++i)
+ {
+ View child = getView(i);
+ int start = child.getStartOffset();
+ int end = child.getEndOffset();
+ if (start <= pos && end > pos)
+ {
+ result = i;
+ break;
+ }
+ }
+ return result;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/GlyphView.java b/libjava/classpath/javax/swing/text/GlyphView.java
new file mode 100644
index 00000000000..f9e60972d84
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/GlyphView.java
@@ -0,0 +1,521 @@
+/* GlyphView.java -- A view to render styled text
+ 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;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+/**
+ * Renders a run of styled text. This {@link View} subclass paints the
+ * characters of the <code>Element</code> it is responsible for using
+ * the style information from that <code>Element</code>.
+ *
+ * @author Roman Kennke (roman@kennke.org)
+ */
+public class GlyphView
+ extends View
+ implements TabableView, Cloneable
+{
+
+ /**
+ * An abstract base implementation for a glyph painter for
+ * <code>GlyphView</code>.
+ */
+ public abstract static class GlyphPainter
+ {
+ /**
+ * Creates a new <code>GlyphPainer</code>.
+ */
+ public GlyphPainter()
+ {
+ }
+
+ /**
+ * Returns the full height of the rendered text.
+ *
+ * @return the full height of the rendered text
+ */
+ public abstract float getHeight(GlyphView view);
+
+ /**
+ * Paints the glyphs.
+ *
+ * @param view the glyph view to paint
+ * @param g the graphics context to use for painting
+ * @param a the allocation of the glyph view
+ * @param p0 the start position (in the model) from which to paint
+ * @param p1 the end position (in the model) to which to paint
+ */
+ public abstract void paint(GlyphView view, Graphics g, Shape a, int p0,
+ int p1);
+
+ /**
+ * Maps a position in the document into the coordinate space of the View.
+ * The output rectangle usually reflects the font height but has a width
+ * of zero.
+ *
+ * @param view the glyph view
+ * @param pos the position of the character in the model
+ * @param a the area that is occupied by the view
+ * @param bias either {@link Position.Bias.Forward} or
+ * {@link Position.Bias.Backward} depending on the preferred
+ * direction bias. If <code>null</code> this defaults to
+ * <code>Position.Bias.Forward</code>
+ *
+ * @return a rectangle that gives the location of the document position
+ * inside the view coordinate space
+ *
+ * @throws BadLocationException if <code>pos</code> is invalid
+ * @throws IllegalArgumentException if b is not one of the above listed
+ * valid values
+ */
+ public abstract Shape modelToView(GlyphView view, int pos, Position.Bias b,
+ Shape a)
+ throws BadLocationException;
+
+ /**
+ * Determine the span of the glyphs from location <code>p0</code> to
+ * location <code>p1</code>. If <code>te</code> is not <code>null</code>,
+ * then TABs are expanded using this <code>TabExpander</code>.
+ * The parameter <code>x</code> is the location at which the view is
+ * located (this is important when using TAB expansion).
+ *
+ * @param view the glyph view
+ * @param p0 the starting location in the document model
+ * @param p0 the end location in the document model
+ * @param te the tab expander to use
+ * @param x the location at which the view is located
+ *
+ * @return the span of the glyphs from location <code>p0</code> to
+ * location <code>p1</code>, possibly using TAB expansion
+ */
+ public abstract float getSpan(GlyphView view, int p0, int p1,
+ TabExpander te, float x);
+
+ }
+
+ /**
+ * The default <code>GlyphPainter</code> used in <code>GlyphView</code>.
+ */
+ static class DefaultGlyphPainter extends GlyphPainter
+ {
+ /**
+ * Returns the full height of the rendered text.
+ *
+ * @return the full height of the rendered text
+ */
+ public float getHeight(GlyphView view)
+ {
+ Font font = view.getFont();
+ FontMetrics metrics = view.getContainer().getFontMetrics(font);
+ float height = metrics.getHeight();
+ return height;
+ }
+
+ /**
+ * Paints the glyphs.
+ *
+ * @param view the glyph view to paint
+ * @param g the graphics context to use for painting
+ * @param a the allocation of the glyph view
+ * @param p0 the start position (in the model) from which to paint
+ * @param p1 the end position (in the model) to which to paint
+ */
+ public void paint(GlyphView view, Graphics g, Shape a, int p0,
+ int p1)
+ {
+ int height = (int) getHeight(view);
+ Segment txt = view.getText(p0, p1);
+ Rectangle bounds = a.getBounds();
+
+ TabExpander tabEx = null;
+ View parent = view.getParent();
+ if (parent instanceof TabExpander)
+ tabEx = (TabExpander) parent;
+
+ // FIXME: Set character attributes like font-family, font-size, colors.
+ Color foreground = view.getForeground();
+ g.setColor(foreground);
+ Utilities.drawTabbedText(txt, bounds.x, bounds.y, g, tabEx,
+ txt.offset);
+ }
+
+ /**
+ * Maps a position in the document into the coordinate space of the View.
+ * The output rectangle usually reflects the font height but has a width
+ * of zero.
+ *
+ * @param view the glyph view
+ * @param pos the position of the character in the model
+ * @param a the area that is occupied by the view
+ * @param bias either {@link Position.Bias.Forward} or
+ * {@link Position.Bias.Backward} depending on the preferred
+ * direction bias. If <code>null</code> this defaults to
+ * <code>Position.Bias.Forward</code>
+ *
+ * @return a rectangle that gives the location of the document position
+ * inside the view coordinate space
+ *
+ * @throws BadLocationException if <code>pos</code> is invalid
+ * @throws IllegalArgumentException if b is not one of the above listed
+ * valid values
+ */
+ public Shape modelToView(GlyphView view, int pos, Position.Bias b,
+ Shape a)
+ throws BadLocationException
+ {
+ Element el = view.getElement();
+ Font font = view.getFont();
+ FontMetrics fm = view.getContainer().getFontMetrics(font);
+ Segment txt = view.getText(el.getStartOffset(), pos);
+ int width = fm.charsWidth(txt.array, txt.offset, txt.count);
+ int height = fm.getHeight();
+ Rectangle bounds = a.getBounds();
+ Rectangle result = new Rectangle(bounds.x + width, bounds.y,
+ bounds.x + width, height);
+ return result;
+ }
+
+ /**
+ * Determine the span of the glyphs from location <code>p0</code> to
+ * location <code>p1</code>. If <code>te</code> is not <code>null</code>,
+ * then TABs are expanded using this <code>TabExpander</code>.
+ * The parameter <code>x</code> is the location at which the view is
+ * located (this is important when using TAB expansion).
+ *
+ * @param view the glyph view
+ * @param p0 the starting location in the document model
+ * @param p0 the end location in the document model
+ * @param te the tab expander to use
+ * @param x the location at which the view is located
+ *
+ * @return the span of the glyphs from location <code>p0</code> to
+ * location <code>p1</code>, possibly using TAB expansion
+ */
+ public float getSpan(GlyphView view, int p0, int p1,
+ TabExpander te, float x)
+ {
+ Element el = view.getElement();
+ Font font = view.getFont();
+ FontMetrics fm = view.getContainer().getFontMetrics(font);
+ Segment txt = view.getText(p0, p1);
+ int span = Utilities.getTabbedTextWidth(txt, fm, (int) x, te, p0);
+ return span;
+ }
+ }
+
+ /**
+ * The GlyphPainer used for painting the glyphs.
+ */
+ GlyphPainter glyphPainter;
+
+ /**
+ * Creates a new <code>GlyphView</code> for the given <code>Element</code>.
+ *
+ * @param element the element that is rendered by this GlyphView
+ */
+ public GlyphView(Element element)
+ {
+ super(element);
+ }
+
+ /**
+ * Returns the <code>GlyphPainter</code> that is used by this
+ * <code>GlyphView</code>. If no <code>GlyphPainer</code> has been installed
+ * <code>null</code> is returned.
+ *
+ * @return the glyph painter that is used by this
+ * glyph view or <code>null</code> if no glyph painter has been
+ * installed
+ */
+ public GlyphPainter getGlyphPainter()
+ {
+ return glyphPainter;
+ }
+
+ /**
+ * Sets the {@link GlyphPainter} to be used for this <code>GlyphView</code>.
+ *
+ * @param painter the glyph painter to be used for this glyph view
+ */
+ public void setGlyphPainter(GlyphPainter painter)
+ {
+ glyphPainter = painter;
+ }
+
+ /**
+ * Checks if a <code>GlyphPainer</code> is installed. If this is not the
+ * case, a default painter is installed.
+ */
+ protected void checkPainter()
+ {
+ if (glyphPainter == null)
+ glyphPainter = new DefaultGlyphPainter();
+ }
+
+ /**
+ * Renders the <code>Element</code> that is associated with this
+ * <code>View</code>.
+ *
+ * @param g the <code>Graphics</code> context to render to
+ * @param a the allocated region for the <code>Element</code>
+ */
+ public void paint(Graphics g, Shape a)
+ {
+ Element el = getElement();
+ checkPainter();
+ getGlyphPainter().paint(this, g, a, el.getStartOffset(),
+ el.getEndOffset());
+ }
+
+
+ /**
+ * Returns the preferred span of the content managed by this
+ * <code>View</code> along the specified <code>axis</code>.
+ *
+ * @param axis the axis
+ *
+ * @return the preferred span of this <code>View</code>.
+ */
+ public float getPreferredSpan(int axis)
+ {
+ Element el = getElement();
+ checkPainter();
+ GlyphPainter painter = getGlyphPainter();
+ TabExpander tabEx = null;
+ View parent = getParent();
+ if (parent instanceof TabExpander)
+ tabEx = (TabExpander) parent;
+ // FIXME: Figure out how to determine the x parameter.
+ float span = painter.getSpan(this, el.getStartOffset(), el.getEndOffset(),
+ tabEx, 0.F);
+ return span;
+ }
+
+ /**
+ * Maps a position in the document into the coordinate space of the View.
+ * The output rectangle usually reflects the font height but has a width
+ * of zero.
+ *
+ * @param pos the position of the character in the model
+ * @param a the area that is occupied by the view
+ * @param b either {@link Position.Bias#Forward} or
+ * {@link Position.Bias#Backward} depending on the preferred
+ * direction bias. If <code>null</code> this defaults to
+ * <code>Position.Bias.Forward</code>
+ *
+ * @return a rectangle that gives the location of the document position
+ * inside the view coordinate space
+ *
+ * @throws BadLocationException if <code>pos</code> is invalid
+ * @throws IllegalArgumentException if b is not one of the above listed
+ * valid values
+ */
+ public Shape modelToView(int pos, Shape a, Position.Bias b)
+ throws BadLocationException
+ {
+ GlyphPainter p = getGlyphPainter();
+ return p.modelToView(this, pos, b, a);
+ }
+
+ /**
+ * Maps coordinates from the <code>View</code>'s space into a position
+ * in the document model.
+ *
+ * @param x the x coordinate in the view space
+ * @param y the y coordinate in the view space
+ * @param a the allocation of this <code>View</code>
+ * @param b the bias to use
+ *
+ * @return the position in the document that corresponds to the screen
+ * coordinates <code>x, y</code>
+ */
+ public int viewToModel(float x, float y, Shape a, Position.Bias[] b)
+ {
+ // FIXME: not implemented
+ return 0;
+ }
+
+ /**
+ * Return the {@link TabExpander} to use.
+ *
+ * @return the {@link TabExpander} to use
+ */
+ public TabExpander getTabExpander()
+ {
+ // TODO: Figure out if this is correct.
+ TabExpander te = null;
+ View parent = getParent();
+
+ if (parent instanceof ParagraphView)
+ te = (ParagraphView) parent;
+
+ return te;
+ }
+
+ /**
+ * Returns the preferred span of this view for tab expansion.
+ *
+ * @param x the location of the view
+ * @param te the tab expander to use
+ *
+ * @return the preferred span of this view for tab expansion
+ */
+ public float getTabbedSpan(float x, TabExpander te)
+ {
+ Element el = getElement();
+ return getGlyphPainter().getSpan(this, el.getStartOffset(),
+ el.getEndOffset(), te, x);
+ }
+
+ /**
+ * Returns the span of a portion of the view. This is used in TAB expansion
+ * for fragments that don't contain TABs.
+ *
+ * @param p0 the start index
+ * @param p1 the end index
+ *
+ * @return the span of the specified portion of the view
+ */
+ public float getPartialSpan(int p0, int p1)
+ {
+ Element el = getElement();
+ Document doc = el.getDocument();
+ Segment seg = new Segment();
+ try
+ {
+ doc.getText(p0, p1 - p0, seg);
+ }
+ catch (BadLocationException ex)
+ {
+ throw new AssertionError("BadLocationException must not be thrown "
+ + "here");
+ }
+ FontMetrics fm = null; // Fetch font metrics somewhere.
+ return Utilities.getTabbedTextWidth(seg, fm, 0, null, p0);
+ }
+
+ /**
+ * Returns the starting offset in the document model of the portion
+ * of text that this view is responsible for.
+ *
+ * @return the starting offset in the document model of the portion
+ * of text that this view is responsible for
+ */
+ public int getBeginIndex()
+ {
+ return getElement().getStartOffset();
+ }
+
+ /**
+ * Returns the end offset in the document model of the portion
+ * of text that this view is responsible for.
+ *
+ * @return the end offset in the document model of the portion
+ * of text that this view is responsible for
+ */
+ public int getEndIndex()
+ {
+ return getElement().getEndOffset();
+ }
+
+ /**
+ * Returns the text segment that this view is responsible for.
+ *
+ * @param p0 the start index in the document model
+ * @param p1 the end index in the document model
+ *
+ * @return the text segment that this view is responsible for
+ */
+ public Segment getText(int p0, int p1)
+ {
+ Segment txt = new Segment();
+ try
+ {
+ getDocument().getText(p0, p1 - p0, txt);
+ }
+ catch (BadLocationException ex)
+ {
+ throw new AssertionError("BadLocationException should not be "
+ + "thrown here. p0 = " + p0 + ", p1 = " + p1);
+ }
+
+ return txt;
+ }
+
+ /**
+ * Returns the font for the text run for which this <code>GlyphView</code>
+ * is responsible.
+ *
+ * @return the font for the text run for which this <code>GlyphView</code>
+ * is responsible
+ */
+ public Font getFont()
+ {
+ Element el = getElement();
+ AttributeSet atts = el.getAttributes();
+ String family = StyleConstants.getFontFamily(atts);
+ int size = StyleConstants.getFontSize(atts);
+ int style = Font.PLAIN;
+ if (StyleConstants.isBold(atts))
+ style |= Font.BOLD;
+ if (StyleConstants.isItalic(atts))
+ style |= Font.ITALIC;
+ Font font = new Font(family, style, size);
+ return font;
+ }
+
+ /**
+ * Returns the foreground color which should be used to paint the text.
+ * This is fetched from the associated element's text attributes using
+ * {@link StyleConstants#getForeground}.
+ *
+ * @return the foreground color which should be used to paint the text
+ */
+ public Color getForeground()
+ {
+ Element el = getElement();
+ AttributeSet atts = el.getAttributes();
+ return StyleConstants.getForeground(atts);
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/IconView.java b/libjava/classpath/javax/swing/text/IconView.java
new file mode 100644
index 00000000000..c7e22b6c3eb
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/IconView.java
@@ -0,0 +1,128 @@
+/* IconView.java -- A view to render icons
+ 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;
+
+import java.awt.Graphics;
+import java.awt.Shape;
+
+// TODO: Implement this class.
+public class IconView
+ extends View
+{
+
+ /**
+ * Creates a new <code>IconView</code> for the given <code>Element</code>.
+ *
+ * @param element the element that is rendered by this IconView
+ */
+ public IconView(Element element)
+ {
+ super(element);
+ }
+
+ /**
+ * Renders the <code>Element</code> that is associated with this
+ * <code>View</code>.
+ *
+ * @param g the <code>Graphics</code> context to render to
+ * @param a the allocated region for the <code>Element</code>
+ */
+ public void paint(Graphics g, Shape a)
+ {
+ // TODO: Implement me.
+ }
+
+ /**
+ * Returns the preferred span of the content managed by this
+ * <code>View</code> along the specified <code>axis</code>.
+ *
+ * @param axis the axis
+ *
+ * @return the preferred span of this <code>View</code>.
+ */
+ public float getPreferredSpan(int axis)
+ {
+ // TODO: Implement me.
+ return 0F;
+ }
+
+ /**
+ * Maps a position in the document into the coordinate space of the View.
+ * The output rectangle usually reflects the font height but has a width
+ * of zero.
+ *
+ * @param pos the position of the character in the model
+ * @param a the area that is occupied by the view
+ * @param b either {@link Position.Bias#Forward} or
+ * {@link Position.Bias#Backward} depending on the preferred
+ * direction bias. If <code>null</code> this defaults to
+ * <code>Position.Bias.Forward</code>
+ *
+ * @return a rectangle that gives the location of the document position
+ * inside the view coordinate space
+ *
+ * @throws BadLocationException if <code>pos</code> is invalid
+ * @throws IllegalArgumentException if b is not one of the above listed
+ * valid values
+ */
+ public Shape modelToView(int pos, Shape a, Position.Bias b)
+ throws BadLocationException
+ {
+ // Implement me.
+ return null;
+ }
+
+ /**
+ * Maps coordinates from the <code>View</code>'s space into a position
+ * in the document model.
+ *
+ * @param x the x coordinate in the view space
+ * @param y the y coordinate in the view space
+ * @param a the allocation of this <code>View</code>
+ * @param b the bias to use
+ *
+ * @return the position in the document that corresponds to the screen
+ * coordinates <code>x, y</code>
+ */
+ public int viewToModel(float x, float y, Shape a, Position.Bias[] b)
+ {
+ // FIXME: not implemented
+ return 0;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/LabelView.java b/libjava/classpath/javax/swing/text/LabelView.java
new file mode 100644
index 00000000000..a10391613cd
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/LabelView.java
@@ -0,0 +1,54 @@
+/* LabelView.java -- A view to render styled text
+ 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;
+
+// TODO: Implement this class.
+public class LabelView
+ extends GlyphView
+{
+ /**
+ * Creates a new <code>GlyphView</code> for the given <code>Element</code>.
+ *
+ * @param element the element that is rendered by this GlyphView
+ */
+ public LabelView(Element element)
+ {
+ super(element);
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/LayoutQueue.java b/libjava/classpath/javax/swing/text/LayoutQueue.java
new file mode 100644
index 00000000000..83433b6eef5
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/LayoutQueue.java
@@ -0,0 +1,115 @@
+/* LayoutQueue.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;
+
+import java.util.LinkedList;
+
+/**
+ * This is a queue which holds {@link Runnable} objects. It is
+ * intended for deferring layout operations.
+ */
+public class LayoutQueue
+{
+ // The default layout queue.
+ private static LayoutQueue defaultQueue = new LayoutQueue();
+
+ // The queue of tasks.
+ private LinkedList list = new LinkedList();
+
+ /**
+ * Create a new layout queue.
+ */
+ public LayoutQueue()
+ {
+ }
+
+ /**
+ * Add a layout task to the queue.
+ */
+ public void addTask(Runnable task)
+ {
+ synchronized (list)
+ {
+ list.addLast(task);
+ list.notify();
+ }
+ }
+
+ /**
+ * Called by a worker thread to retrieve the next layout task. This
+ * will block until a new task is available. This method will
+ * return null if the thread is interrupted while waiting.
+ */
+ protected Runnable waitForWork()
+ {
+ synchronized (list)
+ {
+ while (list.size() == 0)
+ {
+ try
+ {
+ list.wait();
+ }
+ catch (InterruptedException _)
+ {
+ // This seemed like a good idea, but it has not been
+ // tested on the JDK.
+ return null;
+ }
+ }
+ return (Runnable) list.removeFirst();
+ }
+ }
+
+ /**
+ * Return the default layout queue.
+ */
+ public static synchronized LayoutQueue getDefaultQueue()
+ {
+ return defaultQueue;
+ }
+
+ /**
+ * Set the default layout queue.
+ */
+ public static synchronized void setDefaultQueue(LayoutQueue q)
+ {
+ defaultQueue = q;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/ParagraphView.java b/libjava/classpath/javax/swing/text/ParagraphView.java
new file mode 100644
index 00000000000..6c6006a2a0f
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/ParagraphView.java
@@ -0,0 +1,89 @@
+/* ParagraphView.java -- A composite View
+ 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;
+
+/**
+ * A {@link FlowView} that flows it's children horizontally and boxes the rows
+ * vertically.
+ *
+ * @author Roman Kennke (roman@kennke.org)
+ */
+public class ParagraphView extends FlowView implements TabExpander
+{
+ /**
+ * A specialized horizontal <code>BoxView</code> that represents exactly
+ * one row in a <code>ParagraphView</code>.
+ */
+ class Row extends BoxView
+ {
+ /**
+ * Creates a new instance of <code>Row</code>.
+ */
+ Row(Element el)
+ {
+ super(el, X_AXIS);
+ }
+ }
+
+ /**
+ * Creates a new <code>ParagraphView</code> for the given
+ * <code>Element</code>.
+ *
+ * @param element the element that is rendered by this ParagraphView
+ */
+ public ParagraphView(Element element)
+ {
+ super(element, Y_AXIS);
+ }
+
+ public float nextTabStop(float x, int tabOffset)
+ {
+ throw new InternalError("Not implemented yet");
+ }
+
+ /**
+ * Creates a new view that represents a row within a flow.
+ *
+ * @return a view for a new row
+ */
+ protected View createRow()
+ {
+ return new Row(getElement());
+ }
+}