home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1998 November
/
Chip_1998-11_cd.bin
/
tema
/
Cafe
/
jfc.bin
/
CompositeView.java
< prev
next >
Wrap
Text File
|
1998-02-26
|
12KB
|
422 lines
/*
* @(#)CompositeView.java 1.28 98/01/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.28 01/09/98
*/
public abstract class CompositeView extends View {
/**
* Constructs a JCompositeView 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
* @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.
*
* @param offset the starting offset into the child views
* @param length the length
* @param views the child views
*/
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
*/
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
* @see #getView
*/
public int getViewCount() {
return nchildren;
}
/**
* Gets the n-th view in this container.
*
* @param n the number of the view to get
* @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
* @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
* @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
* @param y y coordinate of the view location to convert
* @param a the allocated region to render into
* @return the location within the model that best represents the
* given point in the view
* @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 is before the rectangle range.
*
* @param x the X coordinate
* @param y the Y coordinate
* @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 is after the rectangle range.
*
* @param x the X coordinate
* @param y the Y coordinate
* @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
* @param y the Y coordinate
* @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
* @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
* @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
* @param left the left inset
* @param bottom the bottom inset
* @param right the right inset
*/
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
*/
protected final short getLeftInset() {
return left;
}
/**
* Gets the right inset.
*
* @return the inset
*/
protected final short getRightInset() {
return right;
}
/**
* Gets the top inset.
*
* @return the inset
*/
protected final short getTopInset() {
return top;
}
/**
* Gets the bottom inset.
*
* @return the inset
*/
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;
}