if (cv == child) { // size was being changed on the child, no need to // queue work for it. changing.preferenceChanged(width, height); return; } } int index = getViewIndex(child.getStartOffset(), Position.Bias.Forward); ChildState cs = getChildState(index); cs.preferenceChanged(width, height); LayoutQueue q = getLayoutQueue(); q.addTask(cs); q.addTask(flushTask); } } /** * Sets the size of the view. This should cause * layout of the view if the view caches any layout * information. * <p> * Since the major axis is updated asynchronously and should be * the sum of the tiled children the call is ignored for the major * axis. Since the minor axis is flexible, work is queued to resize * the children if the minor span changes. * * @param width the width >= 0 * @param height the height >= 0 */ public void setSize(float width, float height) { setSpanOnAxis(X_AXIS, width); setSpanOnAxis(Y_AXIS, height); } /** * Retrieves the size of the view along an axis. * * @param axis may be either <code>View.X_AXIS</code> or * <code>View.Y_AXIS</code> * @return the current span of the view along the given axis, >= 0 */ float getSpanOnAxis(int axis) { if (axis == getMajorAxis()) { return majorSpan; } return minorSpan; } /** * Sets the size of the view along an axis. Since the major * axis is updated asynchronously and should be the sum of the * tiled children the call is ignored for the major axis. Since * the minor axis is flexible, work is queued to resize the * children if the minor span changes. * * @param axis may be either <code>View.X_AXIS</code> or * <code>View.Y_AXIS</code> * @param span the span to layout to >= 0 */ void setSpanOnAxis(int axis, float span) { float margin = getInsetSpan(axis); if (axis == getMinorAxis()) { float targetSpan = span - margin; if (targetSpan != minorSpan) { minorSpan = targetSpan; // mark all of the ChildState instances as needing to // resize the child, and queue up work to fix them. int n = getViewCount(); if (n != 0) { LayoutQueue q = getLayoutQueue(); for (int i = 0; i < n; i++) { ChildState cs = getChildState(i); cs.childSizeValid = false; q.addTask(cs); } q.addTask(flushTask); } } } else { // along the major axis the value is ignored // unless the estimatedMajorSpan property is // true. if (estimatedMajorSpan) { majorSpan = span - margin; } } } /** * Render the view using the given allocation and * rendering surface. * <p> * This is implemented to determine whether or not the * desired region to be rendered (i.e. the unclipped * area) is up to date or not. If up-to-date the children * are rendered. If not up-to-date, a task to build * the desired area is placed on the layout queue as * a high priority task. This keeps by event thread * moving by rendering if ready, and postponing until * a later time if not ready (since paint requests * can be rescheduled). * * @param g the rendering surface to use * @param alloc the allocated region to render into * @see View#paint */ public void paint(Graphics g, Shape alloc) { synchronized (locator) { locator.setAllocation(alloc); locator.paintChildren(g); } } /** * 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 >= 0. * 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. * @exception IllegalArgumentException for an invalid axis type */ public float getPreferredSpan(int axis) { float margin = getInsetSpan(axis); if (axis == this.axis) { return majorSpan + margin; } if (prefRequest != null) { View child = prefRequest.getChildView(); return child.getPreferredSpan(axis) + margin; } // nothing is known about the children yet return margin + 30; } /** * Determines the minimum 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 >= 0. * 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. * @exception IllegalArgumentException for an invalid axis type */ public float getMinimumSpan(int axis) { if (axis == this.axis) { return getPreferredSpan(axis); } if (minRequest != null) { View child = minRequest.getChildView(); return child.getMinimumSpan(axis); } // nothing is known about the children yet if (axis == X_AXIS) { return getLeftInset() + getRightInset() + 5; } else { return getTopInset() + getBottomInset() + 5; } } /** * Determines the maximum 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 >= 0. * 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. * @exception IllegalArgumentException for an invalid axis type */ public float getMaximumSpan(int axis) { if (axis == this.axis) { return getPreferredSpan(axis); } return Integer.MAX_VALUE; } /** * Returns the number of views in this view. Since * the default is to not be a composite view this * returns 0. * * @return the number of views >= 0 * @see View#getViewCount */ public int getViewCount() { synchronized(stats) { return stats.size(); } } /** * Gets the nth child view. Since there are no * children by default, this returns null. * * @param n the number of the view to get, >= 0 && < getViewCount() * @return the view */ public View getView(int n) { ChildState cs = getChildState(n); if (cs != null) { return cs.getChildView(); } return null; } /** * Fetches the allocation for the given child view. * This enables finding out where various views * are located, without assuming the views store * their location. This returns null since the * default is to not have any child views. * * @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) { Shape ca = locator.getChildAllocation(index, a); return ca; } /** * Returns the child view index representing the given position in * the model. By default a view has no children so this is implemented * to return -1 to indicate there is no valid child index for any * position. * * @param pos the position >= 0 * @return index of the view representing the given position, or * -1 if no view represents that position * @since 1.3 */ public int getViewIndex(int pos, Position.Bias b) { return getViewIndexAtPosition(pos, b); } /** * 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 * @param b the bias toward the previous character or the * next character represented by the offset, in case the * position is a boundary of two views. * @return the bounding box of the given position is returned * @exception BadLocationException if the given position does * not represent a valid location in the associated document * @exception IllegalArgumentException for an invalid bias argument * @see View#viewToModel */ public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException { int index = getViewIndex(pos, b); Shape ca = locator.getChildAllocation(index, a); // forward to the child view, and make sure we don't // interact with the layout thread by synchronizing // on the child state. ChildState cs = getChildState(index); synchronized (cs) { View cv = cs.getChildView(); Shape v = cv.modelToView(pos, ca, b); return v; } } /** * Provides a mapping from the view coordinate space to the logical * coordinate space of the model. The biasReturn argument will be * filled in to indicate that the point given is closer to the next * character in the model or the previous character in the model. * <p> * This is expected to be called by the GUI thread, holding a * read-lock on the associated model. It is implemented to * locate the child view and determine it's allocation with a * lock on the ChildLocator object, and to call viewToModel * on the child view with a lock on the ChildState object * to avoid interaction with the layout thread. * * @param x the X coordinate >= 0 * @param y the Y coordinate >= 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. The biasReturn argument will be * filled in to indicate that the point given is closer to the next * character in the model or the previous character in the model. */ public int viewToModel(float x, float y, Shape a, Position.Bias[] biasReturn) { int pos; // return position int index; // child index to forward to Shape ca; // child allocation // locate the child view and it's allocation so that // we can forward to it. Make sure the layout thread // doesn't change anything by trying to flush changes // to the parent while the GUI thread is trying to // find the child and it's allocation. synchronized (locator) { index = locator.getViewIndexAtPoint(x, y, a); ca = locator.getChildAllocation(index, a); } // forward to the child view, and make sure we don't // interact with the layout thread by synchronizing // on the child state. ChildState cs = getChildState(index); synchronized (cs) { View v = cs.getChildView(); pos = v.viewToModel(x, y, ca, biasReturn); } return pos; } /** * Provides a way to determine the next visually represented model * location that one might place a caret. Some views may not be visible, * they might not be in the same order found in the model, or they just * might not allow access to some of the locations in the model. * * @param pos the position to convert >= 0 * @param a the allocated region to render into * @param direction the direction from the current position that can * be thought of as the arrow keys typically found on a keyboard; * this may be one of the following: * <ul> * <code>SwingConstants.WEST</code> * <code>SwingConstants.EAST</code> * <code>SwingConstants.NORTH</code> * <code>SwingConstants.SOUTH</code> * </ul> * @param biasRet an array contain the bias that was checked * @return the location within the model that best represents the next * location visual position * @exception BadLocationException * @exception IllegalArgumentException if <code>direction</code> is invalid */ public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, int direction, Position.Bias[] biasRet) throws BadLocationException { return Utilities.getNextVisualPositionFrom( this, pos, b, a, direction, biasRet); } // --- variables ----------------------------------------- /** * The major axis against which the children are * tiled. */ int axis; /** * The children and their layout statistics. */ List<ChildState> stats; /** * Current span along the major axis. This * is also the value returned by getMinimumSize, * getPreferredSize, and getMaximumSize along * the major axis. */ float majorSpan; /** * Is the span along the major axis estimated? */ boolean estimatedMajorSpan; /** * Current span along the minor axis. This * is what layout was done against (i.e. things * are flexible in this direction). */ float minorSpan; /** * Object that manages the offsets of the * children. All locking for management of * child locations is on this object. */ protected ChildLocator locator; float topInset; float bottomInset; float leftInset; float rightInset; ChildState minRequest; ChildState prefRequest; boolean majorChanged; boolean minorChanged; Runnable flushTask; /** * Child that is actively changing size. This often * causes a preferenceChanged, so this is a cache to * possibly speed up the marking the state. It also * helps flag an opportunity to avoid adding to flush * task to the layout queue. */ ChildState changing; /** * A class to manage the effective position of the * child views in a localized area while changes are * being made around the localized area. The AsyncBoxView * may be continuously changing, but the visible area * needs to remain fairly stable until the layout thread * decides to publish an update to the parent. * @since 1.3 */ public class ChildLocator { /** * construct a child locator. */ public ChildLocator() { lastAlloc = new Rectangle(); childAlloc = new Rectangle(); } /** * Notification that a child changed. This can effect * whether or not new offset calculations are needed. * This is called by a ChildState object that has * changed it's major span. This can therefore be * called by multiple threads. */ public synchronized void childChanged(ChildState cs) { if (lastValidOffset == null) { lastValidOffset = cs; } else if (cs.getChildView().getStartOffset() < lastValidOffset.getChildView().getStartOffset()) { lastValidOffset = cs; } } /** * Paint the children that intersect the clip area. */ public synchronized void paintChildren(Graphics g) { Rectangle clip = g.getClipBounds(); float targetOffset = (axis == X_AXIS) ? clip.x - lastAlloc.x : clip.y - lastAlloc.y; int index = getViewIndexAtVisualOffset(targetOffset); int n = getViewCount(); float offs = getChildState(index).getMajorOffset(); for (int i = index; i < n; i++) { ChildState cs = getChildState(i); cs.setMajorOffset(offs); Shape ca = getChildAllocation(i); if (intersectsClip(ca, clip)) { synchronized (cs) { View v = cs.getChildView(); v.paint(g, ca); } } else { // done painting intersection break; } offs += cs.getMajorSpan(); } } /** * Fetch the allocation to use for a child view. * This will update the offsets for all children * not yet updated before the given index. */ public synchronized Shape getChildAllocation(int index, Shape a) { if (a == null) { return null; } setAllocation(a); ChildState cs = getChildState(index); if (lastValidOffset == null) { lastValidOffset = getChildState(0); } if (cs.getChildView().getStartOffset() > lastValidOffset.getChildView().getStartOffset()) { // offsets need to be updated updateChildOffsetsToIndex(index); } Shape ca = getChildAllocation(index); return ca; } Lines 501–1000 of 1420. Previous lines Load more
if (cv == child) { // size was being changed on the child, no need to // queue work for it. changing.preferenceChanged(width, height); return; } } int index = getViewIndex(child.getStartOffset(), Position.Bias.Forward); ChildState cs = getChildState(index); cs.preferenceChanged(width, height); LayoutQueue q = getLayoutQueue(); q.addTask(cs); q.addTask(flushTask); } } /** * Sets the size of the view. This should cause * layout of the view if the view caches any layout * information. * <p> * Since the major axis is updated asynchronously and should be * the sum of the tiled children the call is ignored for the major * axis. Since the minor axis is flexible, work is queued to resize * the children if the minor span changes. * * @param width the width >= 0 * @param height the height >= 0 */ public void setSize(float width, float height) { setSpanOnAxis(X_AXIS, width); setSpanOnAxis(Y_AXIS, height); } /** * Retrieves the size of the view along an axis. * * @param axis may be either <code>View.X_AXIS</code> or * <code>View.Y_AXIS</code> * @return the current span of the view along the given axis, >= 0 */ float getSpanOnAxis(int axis) { if (axis == getMajorAxis()) { return majorSpan; } return minorSpan; } /** * Sets the size of the view along an axis. Since the major * axis is updated asynchronously and should be the sum of the * tiled children the call is ignored for the major axis. Since * the minor axis is flexible, work is queued to resize the * children if the minor span changes. * * @param axis may be either <code>View.X_AXIS</code> or * <code>View.Y_AXIS</code> * @param span the span to layout to >= 0 */ void setSpanOnAxis(int axis, float span) { float margin = getInsetSpan(axis); if (axis == getMinorAxis()) { float targetSpan = span - margin; if (targetSpan != minorSpan) { minorSpan = targetSpan; // mark all of the ChildState instances as needing to // resize the child, and queue up work to fix them. int n = getViewCount(); if (n != 0) { LayoutQueue q = getLayoutQueue(); for (int i = 0; i < n; i++) { ChildState cs = getChildState(i); cs.childSizeValid = false; q.addTask(cs); } q.addTask(flushTask); } } } else { // along the major axis the value is ignored // unless the estimatedMajorSpan property is // true. if (estimatedMajorSpan) { majorSpan = span - margin; } } } /** * Render the view using the given allocation and * rendering surface. * <p> * This is implemented to determine whether or not the * desired region to be rendered (i.e. the unclipped * area) is up to date or not. If up-to-date the children * are rendered. If not up-to-date, a task to build * the desired area is placed on the layout queue as * a high priority task. This keeps by event thread * moving by rendering if ready, and postponing until * a later time if not ready (since paint requests * can be rescheduled). * * @param g the rendering surface to use * @param alloc the allocated region to render into * @see View#paint */ public void paint(Graphics g, Shape alloc) { synchronized (locator) { locator.setAllocation(alloc); locator.paintChildren(g); } } /** * 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 >= 0. * 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. * @exception IllegalArgumentException for an invalid axis type */ public float getPreferredSpan(int axis) { float margin = getInsetSpan(axis); if (axis == this.axis) { return majorSpan + margin; } if (prefRequest != null) { View child = prefRequest.getChildView(); return child.getPreferredSpan(axis) + margin; } // nothing is known about the children yet return margin + 30; } /** * Determines the minimum 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 >= 0. * 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. * @exception IllegalArgumentException for an invalid axis type */ public float getMinimumSpan(int axis) { if (axis == this.axis) { return getPreferredSpan(axis); } if (minRequest != null) { View child = minRequest.getChildView(); return child.getMinimumSpan(axis); } // nothing is known about the children yet if (axis == X_AXIS) { return getLeftInset() + getRightInset() + 5; } else { return getTopInset() + getBottomInset() + 5; } } /** * Determines the maximum 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 >= 0. * 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. * @exception IllegalArgumentException for an invalid axis type */ public float getMaximumSpan(int axis) { if (axis == this.axis) { return getPreferredSpan(axis); } return Integer.MAX_VALUE; } /** * Returns the number of views in this view. Since * the default is to not be a composite view this * returns 0. * * @return the number of views >= 0 * @see View#getViewCount */ public int getViewCount() { synchronized(stats) { return stats.size(); } } /** * Gets the nth child view. Since there are no * children by default, this returns null. * * @param n the number of the view to get, >= 0 && < getViewCount() * @return the view */ public View getView(int n) { ChildState cs = getChildState(n); if (cs != null) { return cs.getChildView(); } return null; } /** * Fetches the allocation for the given child view. * This enables finding out where various views * are located, without assuming the views store * their location. This returns null since the * default is to not have any child views. * * @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) { Shape ca = locator.getChildAllocation(index, a); return ca; } /** * Returns the child view index representing the given position in * the model. By default a view has no children so this is implemented * to return -1 to indicate there is no valid child index for any * position. * * @param pos the position >= 0 * @return index of the view representing the given position, or * -1 if no view represents that position * @since 1.3 */ public int getViewIndex(int pos, Position.Bias b) { return getViewIndexAtPosition(pos, b); } /** * 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 * @param b the bias toward the previous character or the * next character represented by the offset, in case the * position is a boundary of two views. * @return the bounding box of the given position is returned * @exception BadLocationException if the given position does * not represent a valid location in the associated document * @exception IllegalArgumentException for an invalid bias argument * @see View#viewToModel */ public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException { int index = getViewIndex(pos, b); Shape ca = locator.getChildAllocation(index, a); // forward to the child view, and make sure we don't // interact with the layout thread by synchronizing // on the child state. ChildState cs = getChildState(index); synchronized (cs) { View cv = cs.getChildView(); Shape v = cv.modelToView(pos, ca, b); return v; } } /** * Provides a mapping from the view coordinate space to the logical * coordinate space of the model. The biasReturn argument will be * filled in to indicate that the point given is closer to the next * character in the model or the previous character in the model. * <p> * This is expected to be called by the GUI thread, holding a * read-lock on the associated model. It is implemented to * locate the child view and determine it's allocation with a * lock on the ChildLocator object, and to call viewToModel * on the child view with a lock on the ChildState object * to avoid interaction with the layout thread. * * @param x the X coordinate >= 0 * @param y the Y coordinate >= 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. The biasReturn argument will be * filled in to indicate that the point given is closer to the next * character in the model or the previous character in the model. */ public int viewToModel(float x, float y, Shape a, Position.Bias[] biasReturn) { int pos; // return position int index; // child index to forward to Shape ca; // child allocation // locate the child view and it's allocation so that // we can forward to it. Make sure the layout thread // doesn't change anything by trying to flush changes // to the parent while the GUI thread is trying to // find the child and it's allocation. synchronized (locator) { index = locator.getViewIndexAtPoint(x, y, a); ca = locator.getChildAllocation(index, a); } // forward to the child view, and make sure we don't // interact with the layout thread by synchronizing // on the child state. ChildState cs = getChildState(index); synchronized (cs) { View v = cs.getChildView(); pos = v.viewToModel(x, y, ca, biasReturn); } return pos; } /** * Provides a way to determine the next visually represented model * location that one might place a caret. Some views may not be visible, * they might not be in the same order found in the model, or they just * might not allow access to some of the locations in the model. * * @param pos the position to convert >= 0 * @param a the allocated region to render into * @param direction the direction from the current position that can * be thought of as the arrow keys typically found on a keyboard; * this may be one of the following: * <ul> * <code>SwingConstants.WEST</code> * <code>SwingConstants.EAST</code> * <code>SwingConstants.NORTH</code> * <code>SwingConstants.SOUTH</code> * </ul> * @param biasRet an array contain the bias that was checked * @return the location within the model that best represents the next * location visual position * @exception BadLocationException * @exception IllegalArgumentException if <code>direction</code> is invalid */ public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, int direction, Position.Bias[] biasRet) throws BadLocationException { return Utilities.getNextVisualPositionFrom( this, pos, b, a, direction, biasRet); } // --- variables ----------------------------------------- /** * The major axis against which the children are * tiled. */ int axis; /** * The children and their layout statistics. */ List<ChildState> stats; /** * Current span along the major axis. This * is also the value returned by getMinimumSize, * getPreferredSize, and getMaximumSize along * the major axis. */ float majorSpan; /** * Is the span along the major axis estimated? */ boolean estimatedMajorSpan; /** * Current span along the minor axis. This * is what layout was done against (i.e. things * are flexible in this direction). */ float minorSpan; /** * Object that manages the offsets of the * children. All locking for management of * child locations is on this object. */ protected ChildLocator locator; float topInset; float bottomInset; float leftInset; float rightInset; ChildState minRequest; ChildState prefRequest; boolean majorChanged; boolean minorChanged; Runnable flushTask; /** * Child that is actively changing size. This often * causes a preferenceChanged, so this is a cache to * possibly speed up the marking the state. It also * helps flag an opportunity to avoid adding to flush * task to the layout queue. */ ChildState changing; /** * A class to manage the effective position of the * child views in a localized area while changes are * being made around the localized area. The AsyncBoxView * may be continuously changing, but the visible area * needs to remain fairly stable until the layout thread * decides to publish an update to the parent. * @since 1.3 */ public class ChildLocator { /** * construct a child locator. */ public ChildLocator() { lastAlloc = new Rectangle(); childAlloc = new Rectangle(); } /** * Notification that a child changed. This can effect * whether or not new offset calculations are needed. * This is called by a ChildState object that has * changed it's major span. This can therefore be * called by multiple threads. */ public synchronized void childChanged(ChildState cs) { if (lastValidOffset == null) { lastValidOffset = cs; } else if (cs.getChildView().getStartOffset() < lastValidOffset.getChildView().getStartOffset()) { lastValidOffset = cs; } } /** * Paint the children that intersect the clip area. */ public synchronized void paintChildren(Graphics g) { Rectangle clip = g.getClipBounds(); float targetOffset = (axis == X_AXIS) ? clip.x - lastAlloc.x : clip.y - lastAlloc.y; int index = getViewIndexAtVisualOffset(targetOffset); int n = getViewCount(); float offs = getChildState(index).getMajorOffset(); for (int i = index; i < n; i++) { ChildState cs = getChildState(i); cs.setMajorOffset(offs); Shape ca = getChildAllocation(i); if (intersectsClip(ca, clip)) { synchronized (cs) { View v = cs.getChildView(); v.paint(g, ca); } } else { // done painting intersection break; } offs += cs.getMajorSpan(); } } /** * Fetch the allocation to use for a child view. * This will update the offsets for all children * not yet updated before the given index. */ public synchronized Shape getChildAllocation(int index, Shape a) { if (a == null) { return null; } setAllocation(a); ChildState cs = getChildState(index); if (lastValidOffset == null) { lastValidOffset = getChildState(0); } if (cs.getChildView().getStartOffset() > lastValidOffset.getChildView().getStartOffset()) { // offsets need to be updated updateChildOffsetsToIndex(index); } Shape ca = getChildAllocation(index); return ca; }