From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- .../classpath/javax/swing/text/CompositeView.java | 792 +++++++++++++++++++++ 1 file changed, 792 insertions(+) create mode 100644 libjava/classpath/javax/swing/text/CompositeView.java (limited to 'libjava/classpath/javax/swing/text/CompositeView.java') diff --git a/libjava/classpath/javax/swing/text/CompositeView.java b/libjava/classpath/javax/swing/text/CompositeView.java new file mode 100644 index 000000000..ae3c79d2f --- /dev/null +++ b/libjava/classpath/javax/swing/text/CompositeView.java @@ -0,0 +1,792 @@ +/* CompositeView.java -- An abstract view that manages child views + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.awt.Rectangle; +import java.awt.Shape; + +import javax.swing.SwingConstants; + +/** + * An abstract base implementation of {@link View} that manages child + * Views. + * + * @author Roman Kennke (roman@kennke.org) + */ +public abstract class CompositeView + extends View +{ + + /** + * The child views of this CompositeView. + */ + private View[] children; + + /** + * The number of child views. + */ + private int numChildren; + + /** + * The allocation of this View minus its insets. This is + * initialized in {@link #getInsideAllocation} and reused and modified in + * {@link #childAllocation(int, Rectangle)}. + */ + private final Rectangle insideAllocation = new Rectangle(); + + /** + * The insets of this CompositeView. This is initialized + * in {@link #setInsets}. + */ + private short top; + private short bottom; + private short left; + private short right; + + /** + * Creates a new CompositeView for the given + * Element. + * + * @param element the element that is rendered by this CompositeView + */ + public CompositeView(Element element) + { + super(element); + children = new View[0]; + top = 0; + bottom = 0; + left = 0; + right = 0; + } + + /** + * Loads the child views of this CompositeView. 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) + { + if (f != null) + { + 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; + } + // I'd have called replace(0, getViewCount(), newChildren) here + // in order to replace all existing views. However according to + // Harmony's tests this is not what the RI does. + replace(0, 0, newChildren); + } + } + + /** + * Sets the parent of this View. + * In addition to setting the parent, this calls {@link #loadChildren}, if + * this View does not already have its children initialized. + * + * @param parent the parent to set + */ + public void setParent(View parent) + { + super.setParent(parent); + if (parent != null && numChildren == 0) + loadChildren(getViewFactory()); + } + + /** + * Returns the number of child views. + * + * @return the number of child views + */ + public int getViewCount() + { + return numChildren; + } + + /** + * Returns the child view at index n. + * + * @param n the index of the requested child view + * + * @return the child view at index n + */ + public View getView(int n) + { + return children[n]; + } + + /** + * Replaces child views by some other child views. If there are no views to + * remove (length == 0), the result is a simple insert, if + * there are no children to add (view == null) 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) + { + // Make sure we have an array. The Harmony testsuite indicates that we + // have to do something like this. + if (views == null) + views = new View[0]; + + // First we set the parent of the removed children to null. + int endOffset = offset + length; + for (int i = offset; i < endOffset; ++i) + { + if (children[i].getParent() == this) + children[i].setParent(null); + children[i] = null; + } + + // Update the children array. + int delta = views.length - length; + int src = offset + length; + int numMove = numChildren - src; + int dst = src + delta; + if (numChildren + delta > children.length) + { + // Grow array. + int newLength = Math.max(2 * children.length, numChildren + delta); + View[] newChildren = new View[newLength]; + System.arraycopy(children, 0, newChildren, 0, offset); + System.arraycopy(views, 0, newChildren, offset, views.length); + System.arraycopy(children, src, newChildren, dst, numMove); + children = newChildren; + } + else + { + // Patch existing array. + System.arraycopy(children, src, children, dst, numMove); + System.arraycopy(views, 0, children, offset, views.length); + } + numChildren += delta; + + // 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 View. + * + * @param index the index of the child view + * @param a the allocation for this view + * + * @return the allocation for the specified child View + */ + 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 null this defaults to + * Position.Bias.Forward + * + * @return a rectangle that gives the location of the document position + * inside the view coordinate space + * + * @throws BadLocationException if pos 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 + { + boolean backward = bias == Position.Bias.Backward; + int testpos = backward ? Math.max(0, pos - 1) : pos; + + Shape ret = null; + if (! backward || testpos >= getStartOffset()) + { + int childIndex = getViewIndexAtPosition(testpos); + if (childIndex != -1 && childIndex < getViewCount()) + { + View child = getView(childIndex); + if (child != null && testpos >= child.getStartOffset() + && testpos < child.getEndOffset()) + { + Shape childAlloc = getChildAllocation(childIndex, a); + if (childAlloc != null) + { + ret = child.modelToView(pos, childAlloc, bias); + // Handle corner case. + if (ret == null && child.getEndOffset() == pos) + { + childIndex++; + if (childIndex < getViewCount()) + { + child = getView(childIndex); + childAlloc = getChildAllocation(childIndex, a); + ret = child.modelToView(pos, childAlloc, bias); + } + } + } + } + } + } + + if (ret == null) + throw new BadLocationException("Position " + pos + + " is not represented by view.", pos); + + return ret; + } + + /** + * 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 p1 or p2 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 View's space into a position + * in the document model. + * + * @param x the x coordinate in the view space, x >= 0 + * @param y the y coordinate in the view space, y >= 0 + * @param a the allocation of this View + * @param b the bias to use + * + * @return the position in the document that corresponds to the screen + * coordinates x, y >= 0 + */ + public int viewToModel(float x, float y, Shape a, Position.Bias[] b) + { + if (x >= 0 && y >= 0) + { + Rectangle r = getInsideAllocation(a); + View view = getViewAtPoint((int) x, (int) y, r); + return view.viewToModel(x, y, r, b); + } + return 0; + } + + /** + * 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 pos + * @param a + * the allocated region for this view + * @param direction + * the direction from the current position, can be one of the + * following: + * + * @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 pos is not a valid location inside the document + * model + * @throws IllegalArgumentException + * if direction is invalid + */ + public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, + int direction, Position.Bias[] biasRet) + throws BadLocationException + { + 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 pos + * + * @return the index of the child view that represents the specified + * model location + */ + public int getViewIndex(int pos, Position.Bias b) + { + if (b == Position.Bias.Backward) + pos -= 1; + int i = -1; + if (pos >= getStartOffset() && pos < getEndOffset()) + i = getViewIndexAtPosition(pos); + return i; + } + + /** + * Returns true if the specified point lies before the + * given Rectangle, false otherwise. + * + * "Before" 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 true if the specified point lies before the + * given Rectangle, false otherwise + */ + protected abstract boolean isBefore(int x, int y, Rectangle r); + + /** + * Returns true if the specified point lies after the + * given Rectangle, false otherwise. + * + * "After" 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 true if the specified point lies after the + * given Rectangle, false otherwise + */ + protected abstract boolean isAfter(int x, int y, Rectangle r); + + /** + * Returns the child View at the specified location. + * + * @param x the X coordinate + * @param y the Y coordinate + * @param r the inner allocation of this BoxView on entry, + * the allocation of the found child on exit + * + * @return the child View at the specified location + */ + protected abstract View getViewAtPoint(int x, int y, Rectangle r); + + /** + * Computes the allocation for a child View. The parameter + * a stores the allocation of this CompositeView + * and is then adjusted to hold the allocation of the child view. + * + * @param index the index of the child View + * @param a the allocation of this CompositeView before the + * call, the allocation of the child on exit + */ + protected abstract void childAllocation(int index, Rectangle a); + + /** + * Returns the child View that contains the given model + * position. The given Rectangle gives the parent's allocation + * and is changed to the child's allocation on exit. + * + * @param pos the model position to query the child View 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) + { + View view = null; + int i = getViewIndexAtPosition(pos); + if (i >= 0 && i < getViewCount() && a != null) + { + view = getView(i); + childAllocation(i, a); + } + return view; + } + + /** + * Returns the index of the child View for the given model + * position. + * + * @param pos the model position for whicht the child View is + * queried + * + * @return the index of the child View for the given model + * position + */ + protected int getViewIndexAtPosition(int pos) + { + // We have a 1:1 mapping of elements to views here, so we forward + // this to the element. + Element el = getElement(); + return el.getElementIndex(pos); + } + + /** + * Returns the allocation that is given to this CompositeView + * minus this CompositeView'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 CompositeView + * + * @return the allocation that is given to this CompositeView + * minus this CompositeView's insets or + * null if a was null + */ + protected Rectangle getInsideAllocation(Shape a) + { + if (a == null) + return null; + + // Try to avoid allocation of Rectangle here. + Rectangle alloc = a instanceof Rectangle ? (Rectangle) a : 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 = insideAllocation; + inside.x = alloc.x + getLeftInset(); + inside.y = alloc.y + getTopInset(); + inside.width = alloc.width - getLeftInset() - getRightInset(); + inside.height = alloc.height - getTopInset() - getBottomInset(); + return inside; + } + + /** + * Sets the insets defined by attributes in attributes. 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 CompositeView. + * + * @param attributes the attributes from which to query the insets + */ + protected void setParagraphInsets(AttributeSet attributes) + { + top = (short) StyleConstants.getSpaceAbove(attributes); + bottom = (short) StyleConstants.getSpaceBelow(attributes); + left = (short) StyleConstants.getLeftIndent(attributes); + right = (short) StyleConstants.getRightIndent(attributes); + } + + /** + * Sets the insets of this CompositeView. + * + * @param t the top inset + * @param l the left inset + * @param b the bottom inset + * @param r the right inset + */ + protected void setInsets(short t, short l, short b, short r) + { + top = t; + left = l; + bottom = b; + right = r; + } + + /** + * Returns the left inset of this CompositeView. + * + * @return the left inset of this CompositeView + */ + protected short getLeftInset() + { + return left; + } + + /** + * Returns the right inset of this CompositeView. + * + * @return the right inset of this CompositeView + */ + protected short getRightInset() + { + return right; + } + + /** + * Returns the top inset of this CompositeView. + * + * @return the top inset of this CompositeView + */ + protected short getTopInset() + { + return top; + } + + /** + * Returns the bottom inset of this CompositeView. + * + * @return the bottom inset of this CompositeView + */ + protected short getBottomInset() + { + return 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 pos + * @param a the allocated region for this view + * @param direction the direction from the current position, can be one of + * the following: + * + * @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 pos is not a valid location + * inside the document model + * @throws IllegalArgumentException if direction is invalid + */ + protected int getNextNorthSouthVisualPositionFrom(int pos, Position.Bias b, + Shape a, int direction, + Position.Bias[] biasRet) + throws BadLocationException + { + // TODO: It is unknown to me how this method has to be implemented and + // there is no specification telling me how to do it properly. Therefore + // the implementation was done for cases that are known. + // + // If this method ever happens to act silly for your particular case then + // it is likely that it is a cause of not knowing about your case when it + // was implemented first. You are free to fix the behavior. + // + // Here are the assumptions that lead to the implementation: + // If direction is NORTH chose the View preceding the one that contains the + // offset 'pos' (imagine the views are stacked on top of each other where + // the top is 0 and the bottom is getViewCount()-1. + // Consecutively when the direction is SOUTH the View following the one + // the offset 'pos' lies in is questioned. + // + // This limitation is described as PR 27345. + int index = getViewIndex(pos, b); + View v = null; + + if (index == -1) + return pos; + + switch (direction) + { + case NORTH: + // If we cannot calculate a proper offset return the one that was + // provided. + if (index <= 0) + return pos; + + v = getView(index - 1); + break; + case SOUTH: + // If we cannot calculate a proper offset return the one that was + // provided. + if (index >= getViewCount() - 1) + return pos; + + v = getView(index + 1); + break; + default: + throw new IllegalArgumentException(); + } + + return v.getNextVisualPositionFrom(pos, b, a, direction, biasRet); + } + + /** + * 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 pos + * @param a the allocated region for this view + * @param direction the direction from the current position, can be one of + * the following: + * + * @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 pos is not a valid location + * inside the document model + * @throws IllegalArgumentException if direction is invalid + */ + protected int getNextEastWestVisualPositionFrom(int pos, Position.Bias b, + Shape a, int direction, + Position.Bias[] biasRet) + throws BadLocationException + { + // TODO: It is unknown to me how this method has to be implemented and + // there is no specification telling me how to do it properly. Therefore + // the implementation was done for cases that are known. + // + // If this method ever happens to act silly for your particular case then + // it is likely that it is a cause of not knowing about your case when it + // was implemented first. You are free to fix the behavior. + // + // Here are the assumptions that lead to the implementation: + // If direction is EAST increase the offset by one and ask the View to + // which that index belong to calculate the 'next visual position'. + // If the direction is WEST do the same with offset 'pos' being decreased + // by one. + // This behavior will fail in a right-to-left or bidi environment! + // + // This limitation is described as PR 27346. + int index; + + View v = null; + + switch (direction) + { + case EAST: + index = getViewIndex(pos + 1, b); + // If we cannot calculate a proper offset return the one that was + // provided. + if (index == -1) + return pos; + + v = getView(index); + break; + case WEST: + index = getViewIndex(pos - 1, b); + // If we cannot calculate a proper offset return the one that was + // provided. + if (index == -1) + return pos; + + v = getView(index); + break; + default: + throw new IllegalArgumentException(); + } + + return v.getNextVisualPositionFrom(pos, + b, + a, + direction, + biasRet); + } + + /** + * Determines if the next view in horinzontal direction is located to + * the east or west of the view at position pos. Usually + * the Views are laid out from the east to the west, so + * we unconditionally return false 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 pos + * + * @return true if the next View is located + * to the EAST, false otherwise + */ + protected boolean flipEastAndWestAtEnds(int pos, Position.Bias bias) + { + return false; + } +} -- cgit v1.2.3