summaryrefslogtreecommitdiffstats
path: root/libjava/classpath/javax/swing/text/CompositeView.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/javax/swing/text/CompositeView.java')
-rw-r--r--libjava/classpath/javax/swing/text/CompositeView.java652
1 files changed, 652 insertions, 0 deletions
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;
+ }
+}
OpenPOWER on IntegriCloud