home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-06-30 | 12.4 KB | 424 lines |
- /*
- * @(#)CompositeView.java 1.29 98/04/09
- *
- * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
- *
- * This software is the confidential and proprietary information of Sun
- * Microsystems, Inc. ("Confidential Information"). You shall not
- * disclose such Confidential Information and shall use it only in
- * accordance with the terms of the license agreement you entered into
- * with Sun.
- *
- * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
- * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
- * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
- * THIS SOFTWARE OR ITS DERIVATIVES.
- *
- */
- package com.sun.java.swing.text;
-
- import java.util.Vector;
- import java.awt.*;
- import com.sun.java.swing.event.*;
-
- /**
- * A view of a text model that has a children
- * box. If the box is vertical, it might be useful to represent
- * something like a collection of lines or paragraphs. If the
- * box is horizontal, it might be used to represent unwrapped
- * lines.
- *
- * @author Timothy Prinzing
- * @version 1.29 04/09/98
- */
- public abstract class CompositeView extends View {
-
- /**
- * Constructs a CompositeView for the given element.
- *
- * @param elem the element this view is responsible for
- */
- public CompositeView(Element elem) {
- super(elem);
- children = new View[1];
- nchildren = 0;
-
- }
-
- /**
- * Loads all of the children to initialize the view.
- * This is called by the <code>setParent</code> method.
- * Subclasses can reimplement this to initialize their
- * child views in a different manner. The default
- * implementation creates a child view for each
- * child element.
- *
- * @param f the view factory
- */
- protected void loadChildren(ViewFactory f) {
- Element e = getElement();
- int n = e.getElementCount();
- if (n > 0) {
- View[] added = new View[n];
- for (int i = 0; i < n; i++) {
- added[i] = f.create(e.getElement(i));
- }
- replace(0, 0, added);
- }
- }
-
- /**
- * Removes all of the children.
- */
- public void removeAll() {
- replace(0, nchildren, ZERO);
- }
-
- /**
- * Inserts a single child view.
- *
- * @param offs the offset of the view to insert before >= 0
- * @param v the view
- */
- public void insert(int offs, View v) {
- ONE[0] = v;
- replace(offs, 0, ONE);
- }
-
- /**
- * Appends a single child view.
- *
- * @param v the view
- */
- public void append(View v) {
- ONE[0] = v;
- replace(nchildren, 0, ONE);
- }
-
- /**
- * Invalidates the layout and resizes the cache of requests/allocations,
- * allowing for the replacement of child views.
- *
- * @param offset the starting offset into the child views to insert
- * before >= 0
- * @param length the number of existing child views affected >= 0
- * @param views the child views to use as replacements
- */
- public void replace(int offset, int length, View[] views) {
- // update parent reference on removed views
- for (int i = offset; i < offset + length; i++) {
- children[i].setParent(null);
- }
-
- // update the array
- int delta = views.length - length;
- int src = offset + length;
- int nmove = nchildren - src;
- int dest = src + delta;
- if ((nchildren + delta) >= children.length) {
- // need to grow the array
- int newLength = Math.max(2*children.length, nchildren + 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, dest, nmove);
- children = newChildren;
- } else {
- // patch the existing array
- System.arraycopy(children, src, children, dest, nmove);
- System.arraycopy(views, 0, children, offset, views.length);
- }
- nchildren = nchildren + delta;
-
- // update parent reference on added views
- for (int i = 0; i < views.length; i++) {
- views[i].setParent(this);
- }
- }
-
- // --- View methods ---------------------------------------------
-
- /**
- * Sets the parent of the view.
- * This is reimplemented to provide the superclass
- * behavior as well as calling the <code>loadChildren</code>
- * method. The children should not be loaded in the
- * constructor because the act of setting the parent
- * may cause them to try to search up the hierarchy
- * (to get the hosting Container for example).
- *
- * @param parent the parent of the view, null if none
- */
- public void setParent(View parent) {
- super.setParent(parent);
- if (parent != null) {
- ViewFactory f = getViewFactory();
- loadChildren(f);
- }
- }
-
- /**
- * Returns the number of views in this view.
- *
- * @return the number of views >= 0
- * @see #getView
- */
- public int getViewCount() {
- return nchildren;
- }
-
- /**
- * Gets the n-th view in this container.
- *
- * @param n the number of the view to get, >= 0 && < getViewCount()
- * @return the view
- */
- public View getView(int n) {
- return children[n];
- }
-
- /**
- * Fetches the allocation for the given child view.
- * This enables finding out where various views
- * are located, without assuming the views store
- * their location.
- *
- * @param index the index of the child, >= 0 && < getViewCount()
- * @param a the allocation to this view.
- * @return the allocation to the child
- */
- public Shape getChildAllocation(int index, Shape a) {
- Rectangle alloc = a.getBounds();
- childAllocation(index, alloc);
- return alloc;
- }
-
- /**
- * Provides a mapping from the document model coordinate space
- * to the coordinate space of the view mapped to it.
- *
- * @param pos the position to convert >= 0
- * @param a the allocated region to render into
- * @return the bounding box of the given position
- * @exception BadLocationException if the given position does
- * not represent a valid location in the associated document
- * @see View#modelToView
- */
- public Shape modelToView(int pos, Shape a) throws BadLocationException {
- Rectangle alloc = getInsideAllocation(a);
- View v = getViewAtPosition(pos, alloc);
- if (v != null) {
- int p0 = v.getStartOffset();
- int p1 = v.getEndOffset();
- if ((pos >= p0) && (pos < p1)) {
- // get the childs idea of the coordinates
- return v.modelToView(pos, alloc);
- }
- }
- throw new BadLocationException("Position not represented by view", pos);
- }
-
- /**
- * Provides a mapping from the view coordinate space to the logical
- * coordinate space of the model.
- *
- * @param x x coordinate of the view location to convert >= 0
- * @param y y coordinate of the view location to convert >= 0
- * @param a the allocated region to render into
- * @return the location within the model that best represents the
- * given point in the view >= 0
- * @see View#viewToModel
- */
- public int viewToModel(float x, float y, Shape a) {
- Rectangle alloc = getInsideAllocation(a);
- if (isBefore((int) x, (int) y, alloc)) {
- // point is before the range represented
- return getStartOffset();
- } else if (isAfter((int) x, (int) y, alloc)) {
- // point is after the range represented.
- return getEndOffset() -1;
- } else {
- // locate the child and pass along the request
- View v = getViewAtPoint((int) x, (int) y, alloc);
- if (v != null) {
- return v.viewToModel(x, y, alloc);
- }
- }
- return -1;
- }
-
- // --- local methods ----------------------------------------------------
-
-
- /**
- * Tests whether a point lies before the rectangle range.
- *
- * @param x the X coordinate >= 0
- * @param y the Y coordinate >= 0
- * @param alloc the rectangle
- * @return true if the point is before the specified range
- */
- protected abstract boolean isBefore(int x, int y, Rectangle alloc);
-
- /**
- * Tests whether a point lies after the rectangle range.
- *
- * @param x the X coordinate >= 0
- * @param y the Y coordinate >= 0
- * @param alloc the rectangle
- * @return true if the point is after the specified range
- */
- protected abstract boolean isAfter(int x, int y, Rectangle alloc);
-
- /**
- * Fetches the child view at the given point.
- *
- * @param x the X coordinate >= 0
- * @param y the Y coordinate >= 0
- * @param alloc the parent's allocation on entry, which should
- * be changed to the child's allocation on exit
- * @return the child view
- */
- protected abstract View getViewAtPoint(int x, int y, Rectangle alloc);
-
- /**
- * Returns the allocation for a given child.
- *
- * @param index the index of the child, >= 0 && < getViewCount()
- * @param a the allocation to the interior of the box on entry,
- * and the allocation of the view containing the position on exit
- */
- protected abstract void childAllocation(int index, Rectangle a);
-
- /**
- * Fetches the child view that represents the given position in
- * the model. This is implemented to fetch the view in the case
- * where there is a child view for each child element.
- *
- * @param pos the position >= 0
- * @param a the allocation to the interior of the box on entry,
- * and the allocation of the view containing the position on exit
- * @returns the view representing the given position, or
- * null if there isn't one
- */
- protected View getViewAtPosition(int pos, Rectangle a) {
- Element elem = getElement();
- int index = elem.getElementIndex(pos);
- Element child = elem.getElement(index);
- if ((child != null) && (index < getViewCount())) {
- View v = getView(index);
- if (v.getElement() == child) {
- if (a != null) {
- childAllocation(index, a);
- }
- return v;
- }
- }
- return null;
- }
-
- /**
- * Translates the allocation given to the view to the allocation used
- * for composing the interior. This takes into account any
- * margins that were specified.
- *
- * @param a The allocation given to the view.
- * @returns The allocation that represents the inside of the
- * view after the margins have all been removed. If the
- * given allocation was null, the return value is null.
- */
- protected Rectangle getInsideAllocation(Shape a) {
- if (a != null) {
- Rectangle alloc = new Rectangle(a.getBounds());
- alloc.x += left;
- alloc.y += top;
- alloc.width -= left + right;
- alloc.height -= top + bottom;
- return alloc;
- }
- return null;
- }
-
- /**
- * Sets the insets from the paragraph attributes specified in
- * the given attributes.
- *
- * @param attr the attributes
- */
- protected final void setParagraphInsets(AttributeSet attr) {
- // Since version 1.1 doesn't have scaling and assumes
- // a pixel is equal to a point, we just cast the point
- // sizes to integers.
- top = (short) StyleConstants.getSpaceAbove(attr);
- left = (short) StyleConstants.getLeftIndent(attr);
- bottom = (short) StyleConstants.getSpaceBelow(attr);
- right = (short) StyleConstants.getRightIndent(attr);
- }
-
- /**
- * Sets the insets for the view.
- *
- * @param top the top inset >= 0
- * @param left the left inset >= 0
- * @param bottom the bottom inset >= 0
- * @param right the right inset >= 0
- */
- protected final void setInsets(short top, short left, short bottom, short right) {
- this.top = top;
- this.left = left;
- this.right = right;
- this.bottom = bottom;
- }
-
- /**
- * Gets the left inset.
- *
- * @return the inset >= 0
- */
- protected final short getLeftInset() {
- return left;
- }
-
- /**
- * Gets the right inset.
- *
- * @return the inset >= 0
- */
- protected final short getRightInset() {
- return right;
- }
-
- /**
- * Gets the top inset.
- *
- * @return the inset >= 0
- */
- protected final short getTopInset() {
- return top;
- }
-
- /**
- * Gets the bottom inset.
- *
- * @return the inset >= 0
- */
- protected final short getBottomInset() {
- return bottom;
- }
-
-
- // ---- member variables ---------------------------------------------
-
- private static View[] ONE = new View[1];
- private static View[] ZERO = new View[0];
-
- private View[] children;
- private int nchildren;
- private short left;
- private short right;
- private short top;
- private short bottom;
- }
-