/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package javax.swing.text;
import java.awt.*;
import java.util.
Vector;
import javax.swing.event.*;
import javax.swing.
SizeRequirements;
/**
* A View that tries to flow it's children into some
* partially constrained space. This can be used to
* build things like paragraphs, pages, etc. The
* flow is made up of the following pieces of functionality.
* <ul>
* <li>A logical set of child views, which as used as a
* layout pool from which a physical view is formed.
* <li>A strategy for translating the logical view to
* a physical (flowed) view.
* <li>Constraints for the strategy to work against.
* <li>A physical structure, that represents the flow.
* The children of this view are where the pieces of
* of the logical views are placed to create the flow.
* </ul>
*
* @author Timothy Prinzing
* @see View
* @since 1.3
*/
public abstract class
FlowView extends
BoxView {
/**
* Constructs a FlowView for the given element.
*
* @param elem the element that this view is responsible for
* @param axis may be either View.X_AXIS or View.Y_AXIS
*/
public
FlowView(
Element elem, int
axis) {
super(
elem,
axis);
layoutSpan =
Integer.
MAX_VALUE;
strategy = new
FlowStrategy();
}
/**
* Fetches the axis along which views should be
* flowed. By default, this will be the axis
* orthogonal to the axis along which the flow
* rows are tiled (the axis of the default flow
* rows themselves). This is typically used
* by the <code>FlowStrategy</code>.
*/
public int
getFlowAxis() {
if (
getAxis() ==
Y_AXIS) {
return
X_AXIS;
}
return
Y_AXIS;
}
/**
* Fetch the constraining span to flow against for
* the given child index. This is called by the
* FlowStrategy while it is updating the flow.
* A flow can be shaped by providing different values
* for the row constraints. By default, the entire
* span inside of the insets along the flow axis
* is returned.
*
* @param index the index of the row being updated.
* This should be a value >= 0 and < getViewCount().
* @see #getFlowStart
*/
public int
getFlowSpan(int
index) {
return
layoutSpan;
}
/**
* Fetch the location along the flow axis that the
* flow span will start at. This is called by the
* FlowStrategy while it is updating the flow.
* A flow can be shaped by providing different values
* for the row constraints.
* @param index the index of the row being updated.
* This should be a value >= 0 and < getViewCount().
* @see #getFlowSpan
*/
public int
getFlowStart(int
index) {
return 0;
}
/**
* Create a View that should be used to hold a
* a rows worth of children in a flow. This is
* called by the FlowStrategy when new children
* are added or removed (i.e. rows are added or
* removed) in the process of updating the flow.
*/
protected abstract
View createRow();
// ---- BoxView methods -------------------------------------
/**
* Loads all of the children to initialize the view.
* This is called by the <code>setParent</code> method.
* This is reimplemented to not load any children directly
* (as they are created in the process of formatting).
* If the layoutPool variable is null, an instance of
* LogicalView is created to represent the logical view
* that is used in the process of formatting.
*
* @param f the view factory
*/
protected void
loadChildren(
ViewFactory f) {
if (
layoutPool == null) {
layoutPool = new
LogicalView(
getElement());
}
layoutPool.
setParent(this);
// This synthetic insertUpdate call gives the strategy a chance
// to initialize.
strategy.
insertUpdate(this, null, null);
}
/**
* Fetches the child view index representing the given position in
* the model.
*
* @param pos the position >= 0
* @return index of the view representing the given position, or
* -1 if no view represents that position
*/
protected int
getViewIndexAtPosition(int
pos) {
if (
pos >=
getStartOffset() && (
pos <
getEndOffset())) {
for (int
counter = 0;
counter <
getViewCount();
counter++) {
View v =
getView(
counter);
if(
pos >=
v.
getStartOffset() &&
pos <
v.
getEndOffset()) {
return
counter;
}
}
}
return -1;
}
/**
* Lays out the children. If the span along the flow
* axis has changed, layout is marked as invalid which
* which will cause the superclass behavior to recalculate
* the layout along the box axis. The FlowStrategy.layout
* method will be called to rebuild the flow rows as
* appropriate. If the height of this view changes
* (determined by the preferred size along the box axis),
* a preferenceChanged is called. Following all of that,
* the normal box layout of the superclass is performed.
*
* @param width the width to lay out against >= 0. This is
* the width inside of the inset area.
* @param height the height to lay out against >= 0 This
* is the height inside of the inset area.
*/
protected void
layout(int
width, int
height) {
final int
faxis =
getFlowAxis();
int
newSpan;
if (
faxis ==
X_AXIS) {
newSpan =
width;
} else {
newSpan =
height;
}
if (
layoutSpan !=
newSpan) {
layoutChanged(
faxis);
layoutChanged(
getAxis());
layoutSpan =
newSpan;
}
// repair the flow if necessary
if (!
isLayoutValid(
faxis)) {
final int
heightAxis =
getAxis();
int
oldFlowHeight = (
heightAxis ==
X_AXIS)?
getWidth() :
getHeight();
strategy.
layout(this);
int
newFlowHeight = (int)
getPreferredSpan(
heightAxis);
if (
oldFlowHeight !=
newFlowHeight) {
View p =
getParent();
if (
p != null) {
p.
preferenceChanged(this, (
heightAxis ==
X_AXIS), (
heightAxis ==
Y_AXIS));
}
// PENDING(shannonh)
// Temporary fix for 4250847
// Can be removed when TraversalContext is added
Component host =
getContainer();
if (
host != null) {
//nb idk 12/12/2001 host should not be equal to null. We need to add assertion here
host.
repaint();
}
}
}
super.layout(
width,
height);
}
/**
* Calculate requirements along the minor axis. This
* is implemented to forward the request to the logical
* view by calling getMinimumSpan, getPreferredSpan, and
* getMaximumSpan on it.
*/
protected
SizeRequirements calculateMinorAxisRequirements(int
axis,
SizeRequirements r) {
if (
r == null) {
r = new
SizeRequirements();
}
float
pref =
layoutPool.
getPreferredSpan(
axis);
float
min =
layoutPool.
getMinimumSpan(
axis);
// Don't include insets, Box.getXXXSpan will include them.
r.
minimum = (int)
min;
r.
preferred =
Math.
max(
r.
minimum, (int)
pref);
r.
maximum =
Integer.
MAX_VALUE;
r.
alignment = 0.5f;
return
r;
}
// ---- View methods ----------------------------------------------------
/**
* Gives notification that something was inserted into the document
* in a location that this view is responsible for.
*
* @param changes the change information from the associated document
* @param a the current allocation of the view
* @param f the factory to use to rebuild if the view has children
* @see View#insertUpdate
*/
public void
insertUpdate(
DocumentEvent changes,
Shape a,
ViewFactory f) {
layoutPool.
insertUpdate(
changes,
a,
f);
strategy.
insertUpdate(this,
changes,
getInsideAllocation(
a));
}
/**
* Gives notification that something was removed from the document
* in a location that this view is responsible for.
*
* @param changes the change information from the associated document
* @param a the current allocation of the view
* @param f the factory to use to rebuild if the view has children
* @see View#removeUpdate
*/
public void
removeUpdate(
DocumentEvent changes,
Shape a,
ViewFactory f) {
layoutPool.
removeUpdate(
changes,
a,
f);
strategy.
removeUpdate(this,
changes,
getInsideAllocation(
a));
}
/**
* Gives notification from the document that attributes were changed
* in a location that this view is responsible for.
*
* @param changes the change information from the associated document
* @param a the current allocation of the view
* @param f the factory to use to rebuild if the view has children
* @see View#changedUpdate
*/
public void
changedUpdate(
DocumentEvent changes,
Shape a,
ViewFactory f) {
layoutPool.
changedUpdate(
changes,
a,
f);
strategy.
changedUpdate(this,
changes,
getInsideAllocation(
a));
}
/** {@inheritDoc} */
public void
setParent(
View parent) {
super.setParent(
parent);
if (
parent == null
&&
layoutPool != null ) {
layoutPool.
setParent(null);
}
}
// --- variables -----------------------------------------------
/**
* Default constraint against which the flow is
* created against.
*/
protected int
layoutSpan;
/**
* These are the views that represent the child elements
* of the element this view represents (The logical view
* to translate to a physical view). These are not
* directly children of this view. These are either
* placed into the rows directly or used for the purpose
* of breaking into smaller chunks, to form the physical
* view.
*/
protected
View layoutPool;
/**
* The behavior for keeping the flow updated. By
* default this is a singleton shared by all instances
* of FlowView (FlowStrategy is stateless). Subclasses
* can create an alternative strategy, which might keep
* state.
*/
protected
FlowStrategy strategy;
/**
* Strategy for maintaining the physical form
* of the flow. The default implementation is
* completely stateless, and recalculates the
* entire flow if the layout is invalid on the
* given FlowView. Alternative strategies can
* be implemented by subclassing, and might
* perform incremental repair to the layout
* or alternative breaking behavior.
* @since 1.3
*/
public static class
FlowStrategy {
Position damageStart = null;
Vector<
View>
viewBuffer;
void
addDamage(
FlowView fv, int
offset) {
if (
offset >=
fv.
getStartOffset() &&
offset <
fv.
getEndOffset()) {
if (
damageStart == null ||
offset <
damageStart.
getOffset()) {
try {
damageStart =
fv.
getDocument().
createPosition(
offset);
} catch (
BadLocationException e) {
// shouldn't happen since offset is inside view bounds
assert(false);
}
}
}
}
void
unsetDamage() {
damageStart = null;
}
/**
* Gives notification that something was inserted into the document
* in a location that the given flow view is responsible for. The
* strategy should update the appropriate changed region (which
* depends upon the strategy used for repair).
*
* @param e the change information from the associated document
* @param alloc the current allocation of the view inside of the insets.
* This value will be null if the view has not yet been displayed.
* @see View#insertUpdate
*/
public void
insertUpdate(
FlowView fv,
DocumentEvent e,
Rectangle alloc) {
// FlowView.loadChildren() makes a synthetic call into this,
// passing null as e
if (
e != null) {
addDamage(
fv,
e.
getOffset());
}
if (
alloc != null) {
Component host =
fv.
getContainer();
if (
host != null) {
host.
repaint(
alloc.
x,
alloc.
y,
alloc.
width,
alloc.
height);
}
} else {
fv.
preferenceChanged(null, true, true);
}
}
/**
* Gives notification that something was removed from the document
* in a location that the given flow view is responsible for.
*
* @param e the change information from the associated document
* @param alloc the current allocation of the view inside of the insets.
* @see View#removeUpdate
*/
public void
removeUpdate(
FlowView fv,
DocumentEvent e,
Rectangle alloc) {
addDamage(
fv,
e.
getOffset());
if (
alloc != null) {
Component host =
fv.
getContainer();
if (
host != null) {
host.
repaint(
alloc.
x,
alloc.
y,
alloc.
width,
alloc.
height);
}
} else {
fv.
preferenceChanged(null, true, true);
}
}
/**
* Gives notification from the document that attributes were changed
* in a location that this view is responsible for.
*
* @param fv the <code>FlowView</code> containing the changes
* @param e the <code>DocumentEvent</code> describing the changes
* done to the Document
* @param alloc Bounds of the View
* @see View#changedUpdate
*/
public void
changedUpdate(
FlowView fv,
DocumentEvent e,
Rectangle alloc) {
addDamage(
fv,
e.
getOffset());
if (
alloc != null) {
Component host =
fv.
getContainer();
if (
host != null) {
host.
repaint(
alloc.
x,
alloc.
y,
alloc.
width,
alloc.
height);
}
} else {
fv.
preferenceChanged(null, true, true);
}
}
/**
* This method gives flow strategies access to the logical
* view of the FlowView.
*/
protected
View getLogicalView(
FlowView fv) {
return
fv.
layoutPool;
}
/**
* Update the flow on the given FlowView. By default, this causes
* all of the rows (child views) to be rebuilt to match the given
* constraints for each row. This is called by a FlowView.layout
* to update the child views in the flow.
*
* @param fv the view to reflow
*/
public void
layout(
FlowView fv) {
View pool =
getLogicalView(
fv);
int
rowIndex,
p0;
int
p1 =
fv.
getEndOffset();
if (
fv.
majorAllocValid) {
if (
damageStart == null) {
return;
}
// In some cases there's no view at position damageStart, so
// step back and search again. See 6452106 for details.
int
offset =
damageStart.
getOffset();
while ((
rowIndex =
fv.
getViewIndexAtPosition(
offset)) < 0) {
offset--;
}
if (
rowIndex > 0) {
rowIndex--;
}
p0 =
fv.
getView(
rowIndex).
getStartOffset();
} else {
rowIndex = 0;
p0 =
fv.
getStartOffset();
}
reparentViews(
pool,
p0);
viewBuffer = new
Vector<
View>(10, 10);
int
rowCount =
fv.
getViewCount();
while (
p0 <
p1) {
View row;
if (
rowIndex >=
rowCount) {
row =
fv.
createRow();
fv.
append(
row);
} else {
row =
fv.
getView(
rowIndex);
}
p0 =
layoutRow(
fv,
rowIndex,
p0);
rowIndex++;
}
viewBuffer = null;
if (
rowIndex <
rowCount) {
fv.
replace(
rowIndex,
rowCount -
rowIndex, null);
}
unsetDamage();
}
/**
* Creates a row of views that will fit within the
* layout span of the row. This is called by the layout method.
* This is implemented to fill the row by repeatedly calling
* the createView method until the available span has been
* exhausted, a forced break was encountered, or the createView
* method returned null. If the remaining span was exhausted,
* the adjustRow method will be called to perform adjustments
* to the row to try and make it fit into the given span.
*
* @param rowIndex the index of the row to fill in with views. The
* row is assumed to be empty on entry.
* @param pos The current position in the children of
* this views element from which to start.
* @return the position to start the next row
*/
protected int
layoutRow(
FlowView fv, int
rowIndex, int
pos) {
View row =
fv.
getView(
rowIndex);
float
x =
fv.
getFlowStart(
rowIndex);
float
spanLeft =
fv.
getFlowSpan(
rowIndex);
int
end =
fv.
getEndOffset();
TabExpander te = (
fv instanceof
TabExpander) ? (
TabExpander)
fv : null;
final int
flowAxis =
fv.
getFlowAxis();
int
breakWeight =
BadBreakWeight;
float
breakX = 0f;
float
breakSpan = 0f;
int
breakIndex = -1;
int
n = 0;
viewBuffer.
clear();
while (
pos <
end &&
spanLeft >= 0) {
View v =
createView(
fv,
pos, (int)
spanLeft,
rowIndex);
if (
v == null) {
break;
}
int
bw =
v.
getBreakWeight(
flowAxis,
x,
spanLeft);
if (
bw >=
ForcedBreakWeight) {
View w =
v.
breakView(
flowAxis,
pos,
x,
spanLeft);
if (
w != null) {
viewBuffer.
add(
w);
} else if (
n == 0) {
// if the view does not break, and it is the only view
// in a row, use the whole view
viewBuffer.
add(
v);
}
break;
} else if (
bw >=
breakWeight &&
bw >
BadBreakWeight) {
breakWeight =
bw;
breakX =
x;
breakSpan =
spanLeft;
breakIndex =
n;
}
float
chunkSpan;
if (
flowAxis ==
X_AXIS &&
v instanceof
TabableView) {
chunkSpan = ((
TabableView)
v).
getTabbedSpan(
x,
te);
} else {
chunkSpan =
v.
getPreferredSpan(
flowAxis);
}
if (
chunkSpan >
spanLeft &&
breakIndex >= 0) {
// row is too long, and we may break
if (
breakIndex <
n) {
v =
viewBuffer.
get(
breakIndex);
}
for (int
i =
n - 1;
i >=
breakIndex;
i--) {
viewBuffer.
remove(
i);
}
v =
v.
breakView(
flowAxis,
v.
getStartOffset(),
breakX,
breakSpan);
}
spanLeft -=
chunkSpan;
x +=
chunkSpan;
viewBuffer.
add(
v);
pos =
v.
getEndOffset();
n++;
}
View[]
views = new
View[
viewBuffer.
size()];
viewBuffer.
toArray(
views);
row.
replace(0,
row.
getViewCount(),
views);
return (
views.length > 0 ?
row.
getEndOffset() :
pos);
}
/**
* Adjusts the given row if possible to fit within the
* layout span. By default this will try to find the
* highest break weight possible nearest the end of
* the row. If a forced break is encountered, the
* break will be positioned there.
*
* @param rowIndex the row to adjust to the current layout
* span.
* @param desiredSpan the current layout span >= 0
* @param x the location r starts at.
*/
protected void
adjustRow(
FlowView fv, int
rowIndex, int
desiredSpan, int
x) {
final int
flowAxis =
fv.
getFlowAxis();
View r =
fv.
getView(
rowIndex);
int
n =
r.
getViewCount();
int
span = 0;
int
bestWeight =
BadBreakWeight;
int
bestSpan = 0;
int
bestIndex = -1;
View v;
for (int
i = 0;
i <
n;
i++) {
v =
r.
getView(
i);
int
spanLeft =
desiredSpan -
span;
int
w =
v.
getBreakWeight(
flowAxis,
x +
span,
spanLeft);
if ((
w >=
bestWeight) && (
w >
BadBreakWeight)) {
bestWeight =
w;
bestIndex =
i;
bestSpan =
span;
if (
w >=
ForcedBreakWeight) {
// it's a forced break, so there is
// no point in searching further.
break;
}
}
span +=
v.
getPreferredSpan(
flowAxis);
}
if (
bestIndex < 0) {
// there is nothing that can be broken, leave
// it in it's current state.
return;
}
// Break the best candidate view, and patch up the row.
int
spanLeft =
desiredSpan -
bestSpan;
v =
r.
getView(
bestIndex);
v =
v.
breakView(
flowAxis,
v.
getStartOffset(),
x +
bestSpan,
spanLeft);
View[]
va = new
View[1];
va[0] =
v;
View lv =
getLogicalView(
fv);
int
p0 =
r.
getView(
bestIndex).
getStartOffset();
int
p1 =
r.
getEndOffset();
for (int
i = 0;
i <
lv.
getViewCount();
i++) {
View tmpView =
lv.
getView(
i);
if (
tmpView.
getEndOffset() >
p1) {
break;
}
if (
tmpView.
getStartOffset() >=
p0) {
tmpView.
setParent(
lv);
}
}
r.
replace(
bestIndex,
n -
bestIndex,
va);
}
void
reparentViews(
View pool, int
startPos) {
int
n =
pool.
getViewIndex(
startPos,
Position.
Bias.
Forward);
if (
n >= 0) {
for (int
i =
n;
i <
pool.
getViewCount();
i++) {
pool.
getView(
i).
setParent(
pool);
}
}
}
/**
* Creates a view that can be used to represent the current piece
* of the flow. This can be either an entire view from the
* logical view, or a fragment of the logical view.
*
* @param fv the view holding the flow
* @param startOffset the start location for the view being created
* @param spanLeft the about of span left to fill in the row
* @param rowIndex the row the view will be placed into
*/
protected
View createView(
FlowView fv, int
startOffset, int
spanLeft, int
rowIndex) {
// Get the child view that contains the given starting position
View lv =
getLogicalView(
fv);
int
childIndex =
lv.
getViewIndex(
startOffset,
Position.
Bias.
Forward);
View v =
lv.
getView(
childIndex);
if (
startOffset==
v.
getStartOffset()) {
// return the entire view
return
v;
}
// return a fragment.
v =
v.
createFragment(
startOffset,
v.
getEndOffset());
return
v;
}
}
/**
* This class can be used to represent a logical view for
* a flow. It keeps the children updated to reflect the state
* of the model, gives the logical child views access to the
* view hierarchy, and calculates a preferred span. It doesn't
* do any rendering, layout, or model/view translation.
*/
static class
LogicalView extends
CompositeView {
LogicalView(
Element elem) {
super(
elem);
}
protected int
getViewIndexAtPosition(int
pos) {
Element elem =
getElement();
if (
elem.
isLeaf()) {
return 0;
}
return super.getViewIndexAtPosition(
pos);
}
protected void
loadChildren(
ViewFactory f) {
Element elem =
getElement();
if (
elem.
isLeaf()) {
View v = new
LabelView(
elem);
append(
v);
} else {
super.loadChildren(
f);
}
}
/**
* Fetches the attributes to use when rendering. This view
* isn't directly responsible for an element so it returns
* the outer classes attributes.
*/
public
AttributeSet getAttributes() {
View p =
getParent();
return (
p != null) ?
p.
getAttributes() : null;
}
/**
* Determines the preferred span for this view along an
* axis.
*
* @param axis may be either View.X_AXIS or View.Y_AXIS
* @return the span the view would like to be rendered into.
* Typically the view is told to render into the span
* that is returned, although there is no guarantee.
* The parent may choose to resize or break the view.
* @see View#getPreferredSpan
*/
public float
getPreferredSpan(int
axis) {
float
maxpref = 0;
float
pref = 0;
int
n =
getViewCount();
for (int
i = 0;
i <
n;
i++) {
View v =
getView(
i);
pref +=
v.
getPreferredSpan(
axis);
if (
v.
getBreakWeight(
axis, 0,
Integer.
MAX_VALUE) >=
ForcedBreakWeight) {
maxpref =
Math.
max(
maxpref,
pref);
pref = 0;
}
}
maxpref =
Math.
max(
maxpref,
pref);
return
maxpref;
}
/**
* Determines the minimum span for this view along an
* axis. The is implemented to find the minimum unbreakable
* span.
*
* @param axis may be either View.X_AXIS or View.Y_AXIS
* @return the span the view would like to be rendered into.
* Typically the view is told to render into the span
* that is returned, although there is no guarantee.
* The parent may choose to resize or break the view.
* @see View#getPreferredSpan
*/
public float
getMinimumSpan(int
axis) {
float
maxmin = 0;
float
min = 0;
boolean
nowrap = false;
int
n =
getViewCount();
for (int
i = 0;
i <
n;
i++) {
View v =
getView(
i);
if (
v.
getBreakWeight(
axis, 0,
Integer.
MAX_VALUE) ==
BadBreakWeight) {
min +=
v.
getPreferredSpan(
axis);
nowrap = true;
} else if (
nowrap) {
maxmin =
Math.
max(
min,
maxmin);
nowrap = false;
min = 0;
}
if (
v instanceof
ComponentView) {
maxmin =
Math.
max(
maxmin,
v.
getMinimumSpan(
axis));
}
}
maxmin =
Math.
max(
maxmin,
min);
return
maxmin;
}
/**
* Forward the DocumentEvent to the given child view. This
* is implemented to reparent the child to the logical view
* (the children may have been parented by a row in the flow
* if they fit without breaking) and then execute the superclass
* behavior.
*
* @param v the child view to forward the event to.
* @param e the change information from the associated document
* @param a the current allocation of the view
* @param f the factory to use to rebuild if the view has children
* @see #forwardUpdate
* @since 1.3
*/
protected void
forwardUpdateToView(
View v,
DocumentEvent e,
Shape a,
ViewFactory f) {
View parent =
v.
getParent();
v.
setParent(this);
super.forwardUpdateToView(
v,
e,
a,
f);
v.
setParent(
parent);
}
/** {@inheritDoc} */
@
Override
protected void
forwardUpdate(
DocumentEvent.
ElementChange ec,
DocumentEvent e,
Shape a,
ViewFactory f) {
// Update the view responsible for the changed element by invocation of
// super method.
super.forwardUpdate(
ec,
e,
a,
f);
// Re-calculate the update indexes and update the views followed by
// the changed place. Note: we update the views only when insertion or
// removal takes place.
DocumentEvent.
EventType type =
e.
getType();
if (
type ==
DocumentEvent.
EventType.
INSERT ||
type ==
DocumentEvent.
EventType.
REMOVE) {
firstUpdateIndex =
Math.
min((
lastUpdateIndex + 1), (
getViewCount() - 1));
lastUpdateIndex =
Math.
max((
getViewCount() - 1), 0);
for (int
i =
firstUpdateIndex;
i <=
lastUpdateIndex;
i++) {
View v =
getView(
i);
if (
v != null) {
v.
updateAfterChange();
}
}
}
}
// The following methods don't do anything useful, they
// simply keep the class from being abstract.
/**
* Renders using the given rendering surface and area on that
* surface. This is implemented to do nothing, the logical
* view is never visible.
*
* @param g the rendering surface to use
* @param allocation the allocated region to render into
* @see View#paint
*/
public void
paint(
Graphics g,
Shape allocation) {
}
/**
* Tests whether a point lies before the rectangle range.
* Implemented to return false, as hit detection is not
* performed on the logical view.
*
* @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 boolean
isBefore(int
x, int
y,
Rectangle alloc) {
return false;
}
/**
* Tests whether a point lies after the rectangle range.
* Implemented to return false, as hit detection is not
* performed on the logical view.
*
* @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 boolean
isAfter(int
x, int
y,
Rectangle alloc) {
return false;
}
/**
* Fetches the child view at the given point.
* Implemented to return null, as hit detection is not
* performed on the logical view.
*
* @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
View getViewAtPoint(int
x, int
y,
Rectangle alloc) {
return null;
}
/**
* Returns the allocation for a given child.
* Implemented to do nothing, as the logical view doesn't
* perform layout on the children.
*
* @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 child view at the index on exit.
*/
protected void
childAllocation(int
index,
Rectangle a) {
}
}
}