| /* FlowView.java -- A composite View |
| Copyright (C) 2005 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.Component; |
| import java.awt.Graphics; |
| import java.awt.Rectangle; |
| import java.awt.Shape; |
| |
| import javax.swing.SizeRequirements; |
| import javax.swing.event.DocumentEvent; |
| |
| /** |
| * A <code>View</code> that can flows it's children into it's layout space. |
| * |
| * The <code>FlowView</code> manages a set of logical views (that are |
| * the children of the {@link #layoutPool} field). These are translated |
| * at layout time into a set of physical views. These are the views that |
| * are managed as the real child views. Each of these child views represents |
| * a row and are laid out within a box using the superclasses behaviour. |
| * The concrete implementation of the rows must be provided by subclasses. |
| * |
| * @author Roman Kennke (roman@kennke.org) |
| */ |
| public abstract class FlowView extends BoxView |
| { |
| /** |
| * A strategy for translating the logical views of a <code>FlowView</code> |
| * into the real views. |
| */ |
| public static class FlowStrategy |
| { |
| /** |
| * Creates a new instance of <code>FlowStragegy</code>. |
| */ |
| public FlowStrategy() |
| { |
| // Nothing to do here. |
| } |
| |
| /** |
| * Receives notification from a <code>FlowView</code> that some content |
| * has been inserted into the document at a location that the |
| * <code>FlowView</code> is responsible for. |
| * |
| * The default implementation simply calls {@link #layout}. |
| * |
| * @param fv the flow view that sends the notification |
| * @param e the document event describing the change |
| * @param alloc the current allocation of the flow view |
| */ |
| public void insertUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) |
| { |
| if (alloc == null) |
| { |
| fv.layoutChanged(X_AXIS); |
| fv.layoutChanged(Y_AXIS); |
| } |
| else |
| { |
| Component host = fv.getContainer(); |
| if (host != null) |
| host.repaint(alloc.x, alloc.y, alloc.width, alloc.height); |
| } |
| } |
| |
| /** |
| * Receives notification from a <code>FlowView</code> that some content |
| * has been removed from the document at a location that the |
| * <code>FlowView</code> is responsible for. |
| * |
| * The default implementation simply calls {@link #layout}. |
| * |
| * @param fv the flow view that sends the notification |
| * @param e the document event describing the change |
| * @param alloc the current allocation of the flow view |
| */ |
| public void removeUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) |
| { |
| if (alloc == null) |
| { |
| fv.layoutChanged(X_AXIS); |
| fv.layoutChanged(Y_AXIS); |
| } |
| else |
| { |
| Component host = fv.getContainer(); |
| if (host != null) |
| host.repaint(alloc.x, alloc.y, alloc.width, alloc.height); |
| } |
| } |
| |
| /** |
| * Receives notification from a <code>FlowView</code> that some attributes |
| * have changed in the document at a location that the |
| * <code>FlowView</code> is responsible for. |
| * |
| * The default implementation simply calls {@link #layout}. |
| * |
| * @param fv the flow view that sends the notification |
| * @param e the document event describing the change |
| * @param alloc the current allocation of the flow view |
| */ |
| public void changedUpdate(FlowView fv, DocumentEvent e, Rectangle alloc) |
| { |
| if (alloc == null) |
| { |
| fv.layoutChanged(X_AXIS); |
| fv.layoutChanged(Y_AXIS); |
| } |
| else |
| { |
| Component host = fv.getContainer(); |
| if (host != null) |
| host.repaint(alloc.x, alloc.y, alloc.width, alloc.height); |
| } |
| } |
| |
| /** |
| * Returns the logical view of the managed <code>FlowView</code>. |
| * |
| * @param fv the flow view for which to return the logical view |
| * |
| * @return the logical view of the managed <code>FlowView</code> |
| */ |
| protected View getLogicalView(FlowView fv) |
| { |
| return fv.layoutPool; |
| } |
| |
| /** |
| * Performs the layout for the whole view. By default this rebuilds |
| * all the physical views from the logical views of the managed FlowView. |
| * |
| * This is called by {@link FlowView#layout} to update the layout of |
| * the view. |
| * |
| * @param fv the flow view for which we perform the layout |
| */ |
| public void layout(FlowView fv) |
| { |
| int start = fv.getStartOffset(); |
| int end = fv.getEndOffset(); |
| |
| // Preserve the views from the logical view from beeing removed. |
| View lv = getLogicalView(fv); |
| int viewCount = lv.getViewCount(); |
| for (int i = 0; i < viewCount; i++) |
| { |
| View v = lv.getView(i); |
| v.setParent(lv); |
| } |
| |
| // Then remove all views from the flow view. |
| fv.removeAll(); |
| |
| for (int rowIndex = 0; start < end; rowIndex++) |
| { |
| View row = fv.createRow(); |
| fv.append(row); |
| int next = layoutRow(fv, rowIndex, start); |
| if (row.getViewCount() == 0) |
| { |
| row.append(createView(fv, start, Integer.MAX_VALUE, rowIndex)); |
| next = row.getEndOffset(); |
| } |
| if (start < next) |
| start = next; |
| else |
| assert false: "May not happen"; |
| } |
| } |
| |
| /** |
| * Lays out one row of the flow view. This is called by {@link #layout} to |
| * fill one row with child views until the available span is exhausted. The |
| * default implementation fills the row by calling |
| * {@link #createView(FlowView, int, int, int)} until the available space is |
| * exhausted, a forced break is encountered or there are no more views in |
| * the logical view. If the available space is exhausted, |
| * {@link #adjustRow(FlowView, int, int, int)} is called to fit the row into |
| * the available span. |
| * |
| * @param fv the flow view for which we perform the layout |
| * @param rowIndex the index of the row |
| * @param pos the model position for the beginning of the row |
| * @return the start position of the next row |
| */ |
| protected int layoutRow(FlowView fv, int rowIndex, int pos) |
| { |
| View row = fv.getView(rowIndex); |
| int axis = fv.getFlowAxis(); |
| int span = fv.getFlowSpan(rowIndex); |
| int x = fv.getFlowStart(rowIndex); |
| int end = fv.getEndOffset(); |
| |
| // Needed for adjusting indentation in adjustRow(). |
| int preX = x; |
| int availableSpan = span; |
| |
| TabExpander tabExp = fv instanceof TabExpander ? (TabExpander) fv : null; |
| |
| boolean forcedBreak = false; |
| while (pos < end && span >= 0) |
| { |
| View view = createView(fv, pos, span, rowIndex); |
| if (view == null |
| || (span == 0 && view.getPreferredSpan(axis) > 0)) |
| break; |
| |
| int viewSpan; |
| if (axis == X_AXIS && view instanceof TabableView) |
| viewSpan = (int) ((TabableView) view).getTabbedSpan(x, tabExp); |
| else |
| viewSpan = (int) view.getPreferredSpan(axis); |
| |
| // Break if the line if the view does not fit in this row or the |
| // line just must be broken. |
| int breakWeight = view.getBreakWeight(axis, pos, span); |
| if (breakWeight >= ForcedBreakWeight) |
| { |
| int rowViewCount = row.getViewCount(); |
| if (rowViewCount > 0) |
| { |
| view = view.breakView(axis, pos, x, span); |
| if (view != null) |
| { |
| if (axis == X_AXIS && view instanceof TabableView) |
| viewSpan = |
| (int) ((TabableView) view).getTabbedSpan(x, tabExp); |
| else |
| viewSpan = (int) view.getPreferredSpan(axis); |
| } |
| else |
| viewSpan = 0; |
| } |
| forcedBreak = true; |
| } |
| span -= viewSpan; |
| x += viewSpan; |
| if (view != null) |
| { |
| row.append(view); |
| pos = view.getEndOffset(); |
| } |
| if (forcedBreak) |
| break; |
| } |
| |
| if (span < 0) |
| adjustRow(fv, rowIndex, availableSpan, preX); |
| else if (row.getViewCount() == 0) |
| { |
| View view = createView(fv, pos, Integer.MAX_VALUE, rowIndex); |
| row.append(view); |
| } |
| return row.getEndOffset(); |
| } |
| |
| /** |
| * Creates physical views that form the rows of the flow view. This |
| * can be an entire view from the logical view (if it fits within the |
| * available span), a fragment of such a view (if it doesn't fit in the |
| * available span and can be broken down) or <code>null</code> (if it does |
| * not fit in the available span and also cannot be broken down). |
| * |
| * The default implementation fetches the logical view at the specified |
| * <code>startOffset</code>. If that view has a different startOffset than |
| * specified in the argument, a fragment is created using |
| * {@link View#createFragment(int, int)} that has the correct startOffset |
| * and the logical view's endOffset. |
| * |
| * @param fv the flow view |
| * @param startOffset the start offset for the view to be created |
| * @param spanLeft the available span |
| * @param rowIndex the index of the row |
| * |
| * @return a view to fill the row with, or <code>null</code> if there |
| * is no view or view fragment that fits in the available span |
| */ |
| protected View createView(FlowView fv, int startOffset, int spanLeft, |
| int rowIndex) |
| { |
| View logicalView = getLogicalView(fv); |
| int index = logicalView.getViewIndex(startOffset, |
| Position.Bias.Forward); |
| View retVal = logicalView.getView(index); |
| if (retVal.getStartOffset() != startOffset) |
| retVal = retVal.createFragment(startOffset, retVal.getEndOffset()); |
| return retVal; |
| } |
| |
| /** |
| * Tries to adjust the specified row to fit within the desired span. The |
| * default implementation iterates through the children of the specified |
| * row to find the view that has the highest break weight and - if there |
| * is more than one view with such a break weight - which is nearest to |
| * the end of the row. If there is such a view that has a break weight > |
| * {@link View#BadBreakWeight}, this view is broken using the |
| * {@link View#breakView(int, int, float, float)} method and this view and |
| * all views after the now broken view are replaced by the broken view. |
| * |
| * @param fv the flow view |
| * @param rowIndex the index of the row to be adjusted |
| * @param desiredSpan the layout span |
| * @param x the X location at which the row starts |
| */ |
| protected void adjustRow(FlowView fv, int rowIndex, int desiredSpan, int x) { |
| // Determine the last view that has the highest break weight. |
| int axis = fv.getFlowAxis(); |
| View row = fv.getView(rowIndex); |
| int count = row.getViewCount(); |
| int breakIndex = -1; |
| int breakWeight = BadBreakWeight; |
| int breakSpan = 0; |
| int currentSpan = 0; |
| for (int i = 0; i < count; ++i) |
| { |
| View view = row.getView(i); |
| int spanLeft = desiredSpan - currentSpan; |
| int weight = view.getBreakWeight(axis, x + currentSpan, spanLeft); |
| if (weight >= breakWeight && weight > BadBreakWeight) |
| { |
| breakIndex = i; |
| breakSpan = currentSpan; |
| breakWeight = weight; |
| if (weight >= ForcedBreakWeight) |
| // Don't search further. |
| break; |
| } |
| currentSpan += view.getPreferredSpan(axis); |
| } |
| |
| // If there is a potential break location found, break the row at |
| // this location. |
| if (breakIndex >= 0) |
| { |
| int spanLeft = desiredSpan - breakSpan; |
| View toBeBroken = row.getView(breakIndex); |
| View brokenView = toBeBroken.breakView(axis, |
| toBeBroken.getStartOffset(), |
| x + breakSpan, spanLeft); |
| View lv = getLogicalView(fv); |
| for (int i = breakIndex; i < count; i++) |
| { |
| View tmp = row.getView(i); |
| if (contains(lv, tmp)) |
| tmp.setParent(lv); |
| else if (tmp.getViewCount() > 0) |
| reparent(tmp, lv); |
| } |
| row.replace(breakIndex, count - breakIndex, |
| new View[]{ brokenView }); |
| } |
| |
| } |
| |
| /** |
| * Helper method to determine if one view contains another as child. |
| */ |
| private boolean contains(View view, View child) |
| { |
| boolean ret = false; |
| int n = view.getViewCount(); |
| for (int i = 0; i < n && ret == false; i++) |
| { |
| if (view.getView(i) == child) |
| ret = true; |
| } |
| return ret; |
| } |
| |
| /** |
| * Helper method that reparents the <code>view</code> and all of its |
| * decendents to the <code>parent</code> (the logical view). |
| * |
| * @param view the view to reparent |
| * @param parent the new parent |
| */ |
| private void reparent(View view, View parent) |
| { |
| int n = view.getViewCount(); |
| for (int i = 0; i < n; i++) |
| { |
| View tmp = view.getView(i); |
| if (contains(parent, tmp)) |
| tmp.setParent(parent); |
| else |
| reparent(tmp, parent); |
| } |
| } |
| } |
| |
| /** |
| * This special subclass of <code>View</code> is used to represent |
| * the logical representation of this view. It does not support any |
| * visual representation, this is handled by the physical view implemented |
| * in the <code>FlowView</code>. |
| */ |
| class LogicalView extends CompositeView |
| { |
| /** |
| * Creates a new LogicalView instance. |
| */ |
| LogicalView(Element el) |
| { |
| super(el); |
| } |
| |
| /** |
| * Overridden to return the attributes of the parent |
| * (== the FlowView instance). |
| */ |
| public AttributeSet getAttributes() |
| { |
| View p = getParent(); |
| return p != null ? p.getAttributes() : null; |
| } |
| |
| protected void childAllocation(int index, Rectangle a) |
| { |
| // Nothing to do here (not visual). |
| } |
| |
| protected View getViewAtPoint(int x, int y, Rectangle r) |
| { |
| // Nothing to do here (not visual). |
| return null; |
| } |
| |
| protected boolean isAfter(int x, int y, Rectangle r) |
| { |
| // Nothing to do here (not visual). |
| return false; |
| } |
| |
| protected boolean isBefore(int x, int y, Rectangle r) |
| { |
| // Nothing to do here (not visual). |
| return false; |
| } |
| |
| public float getPreferredSpan(int axis) |
| { |
| float max = 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) |
| { |
| max = Math.max(max, pref); |
| pref = 0; |
| } |
| } |
| max = Math.max(max, pref); |
| return max; |
| } |
| |
| public float getMinimumSpan(int axis) |
| { |
| float max = 0; |
| float min = 0; |
| boolean wrap = true; |
| 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); |
| wrap = false; |
| } |
| else if (! wrap) |
| { |
| max = Math.max(min, max); |
| wrap = true; |
| min = 0; |
| } |
| } |
| max = Math.max(max, min); |
| return max; |
| } |
| |
| public void paint(Graphics g, Shape s) |
| { |
| // Nothing to do here (not visual). |
| } |
| |
| /** |
| * Overridden to handle possible leaf elements. |
| */ |
| protected void loadChildren(ViewFactory f) |
| { |
| Element el = getElement(); |
| if (el.isLeaf()) |
| { |
| View v = new LabelView(el); |
| append(v); |
| } |
| else |
| super.loadChildren(f); |
| } |
| |
| /** |
| * Overridden to reparent the children to this logical view, in case |
| * they have been parented by a row. |
| */ |
| protected void forwardUpdateToView(View v, DocumentEvent e, Shape a, |
| ViewFactory f) |
| { |
| v.setParent(this); |
| super.forwardUpdateToView(v, e, a, f); |
| } |
| |
| /** |
| * Overridden to handle possible leaf element. |
| */ |
| protected int getViewIndexAtPosition(int pos) |
| { |
| int index = 0; |
| if (! getElement().isLeaf()) |
| index = super.getViewIndexAtPosition(pos); |
| return index; |
| } |
| } |
| |
| /** |
| * The shared instance of FlowStrategy. |
| */ |
| static final FlowStrategy sharedStrategy = new FlowStrategy(); |
| |
| /** |
| * The span of the <code>FlowView</code> that should be flowed. |
| */ |
| protected int layoutSpan; |
| |
| /** |
| * Represents the logical child elements of this view, encapsulated within |
| * one parent view (an instance of a package private <code>LogicalView</code> |
| * class). These will be translated to a set of real views that are then |
| * displayed on screen. This translation is performed by the inner class |
| * {@link FlowStrategy}. |
| */ |
| protected View layoutPool; |
| |
| /** |
| * The <code>FlowStrategy</code> to use for translating between the |
| * logical and physical view. |
| */ |
| protected FlowStrategy strategy; |
| |
| /** |
| * Creates a new <code>FlowView</code> for the given |
| * <code>Element</code> and <code>axis</code>. |
| * |
| * @param element the element that is rendered by this FlowView |
| * @param axis the axis along which the view is tiled, either |
| * <code>View.X_AXIS</code> or <code>View.Y_AXIS</code>, the flow |
| * axis is orthogonal to this one |
| */ |
| public FlowView(Element element, int axis) |
| { |
| super(element, axis); |
| strategy = sharedStrategy; |
| layoutSpan = Short.MAX_VALUE; |
| } |
| |
| /** |
| * Returns the axis along which the view should be flowed. This is |
| * orthogonal to the axis along which the boxes are tiled. |
| * |
| * @return the axis along which the view should be flowed |
| */ |
| public int getFlowAxis() |
| { |
| int axis = getAxis(); |
| int flowAxis; |
| |
| if (axis == X_AXIS) |
| flowAxis = Y_AXIS; |
| else |
| flowAxis = X_AXIS; |
| |
| return flowAxis; |
| |
| } |
| |
| /** |
| * Returns the span of the flow for the specified child view. A flow |
| * layout can be shaped by providing different span values for different |
| * child indices. The default implementation returns the entire available |
| * span inside the view. |
| * |
| * @param index the index of the child for which to return the span |
| * |
| * @return the span of the flow for the specified child view |
| */ |
| public int getFlowSpan(int index) |
| { |
| return layoutSpan; |
| } |
| |
| /** |
| * Returns the location along the flow axis where the flow span starts |
| * given a child view index. The flow can be shaped by providing |
| * different values here. |
| * |
| * @param index the index of the child for which to return the flow location |
| * |
| * @return the location along the flow axis where the flow span starts |
| */ |
| public int getFlowStart(int index) |
| { |
| return 0; |
| } |
| |
| /** |
| * Creates a new view that represents a row within a flow. |
| * |
| * @return a view for a new row |
| */ |
| protected abstract View createRow(); |
| |
| /** |
| * Loads the children of this view. The <code>FlowView</code> does not |
| * directly load its children. Instead it creates a logical view |
| * ({@link #layoutPool}) which is filled by the logical child views. |
| * The real children are created at layout time and each represent one |
| * row. |
| * |
| * This method is called by {@link View#setParent} in order to initialize |
| * the view. |
| * |
| * @param vf the view factory to use for creating the child views |
| */ |
| protected void loadChildren(ViewFactory vf) |
| { |
| if (layoutPool == null) |
| { |
| layoutPool = new LogicalView(getElement()); |
| } |
| layoutPool.setParent(this); |
| // Initialize the flow strategy. |
| strategy.insertUpdate(this, null, null); |
| } |
| |
| /** |
| * Performs the layout of this view. If the span along the flow axis changed, |
| * this first calls {@link FlowStrategy#layout} in order to rebuild the |
| * rows of this view. Then the superclass's behaviour is called to arrange |
| * the rows within the box. |
| * |
| * @param width the width of the view |
| * @param height the height of the view |
| */ |
| protected void layout(int width, int height) |
| { |
| int flowAxis = getFlowAxis(); |
| int span; |
| if (flowAxis == X_AXIS) |
| span = (int) width; |
| else |
| span = (int) height; |
| |
| if (layoutSpan != span) |
| { |
| layoutChanged(flowAxis); |
| layoutChanged(getAxis()); |
| layoutSpan = span; |
| } |
| |
| if (! isLayoutValid(flowAxis)) |
| { |
| int axis = getAxis(); |
| int oldSpan = axis == X_AXIS ? getWidth() : getHeight(); |
| strategy.layout(this); |
| int newSpan = (int) getPreferredSpan(axis); |
| if (oldSpan != newSpan) |
| { |
| View parent = getParent(); |
| if (parent != null) |
| parent.preferenceChanged(this, axis == X_AXIS, axis == Y_AXIS); |
| } |
| } |
| |
| super.layout(width, height); |
| } |
| |
| /** |
| * Receice notification that some content has been inserted in the region |
| * that this view is responsible for. This calls |
| * {@link FlowStrategy#insertUpdate}. |
| * |
| * @param changes the document event describing the changes |
| * @param a the current allocation of the view |
| * @param vf the view factory that is used for creating new child views |
| */ |
| public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory vf) |
| { |
| // First we must send the insertUpdate to the logical view so it can |
| // be updated accordingly. |
| layoutPool.insertUpdate(changes, a, vf); |
| strategy.insertUpdate(this, changes, getInsideAllocation(a)); |
| } |
| |
| /** |
| * Receice notification that some content has been removed from the region |
| * that this view is responsible for. This calls |
| * {@link FlowStrategy#removeUpdate}. |
| * |
| * @param changes the document event describing the changes |
| * @param a the current allocation of the view |
| * @param vf the view factory that is used for creating new child views |
| */ |
| public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory vf) |
| { |
| layoutPool.removeUpdate(changes, a, vf); |
| strategy.removeUpdate(this, changes, getInsideAllocation(a)); |
| } |
| |
| /** |
| * Receice notification that some attributes changed in the region |
| * that this view is responsible for. This calls |
| * {@link FlowStrategy#changedUpdate}. |
| * |
| * @param changes the document event describing the changes |
| * @param a the current allocation of the view |
| * @param vf the view factory that is used for creating new child views |
| */ |
| public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory vf) |
| { |
| layoutPool.changedUpdate(changes, a, vf); |
| strategy.changedUpdate(this, changes, getInsideAllocation(a)); |
| } |
| |
| /** |
| * Returns the index of the child <code>View</code> for the given model |
| * position. |
| * |
| * This is implemented to iterate over the children of this |
| * view (the rows) and return the index of the first view that contains |
| * the given position. |
| * |
| * @param pos the model position for whicht the child <code>View</code> is |
| * queried |
| * |
| * @return the index of the child <code>View</code> for the given model |
| * position |
| */ |
| protected int getViewIndexAtPosition(int pos) |
| { |
| // First make sure we have a valid layout. |
| if (!isAllocationValid()) |
| layout(getWidth(), getHeight()); |
| |
| int count = getViewCount(); |
| int result = -1; |
| |
| for (int i = 0; i < count; ++i) |
| { |
| View child = getView(i); |
| int start = child.getStartOffset(); |
| int end = child.getEndOffset(); |
| if (start <= pos && end > pos) |
| { |
| result = i; |
| break; |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Calculates the size requirements of this <code>BoxView</code> along |
| * its minor axis, that is the axis opposite to the axis specified in the |
| * constructor. |
| * |
| * This is overridden and forwards the request to the logical view. |
| * |
| * @param axis the axis that is examined |
| * @param r the <code>SizeRequirements</code> object to hold the result, |
| * if <code>null</code>, a new one is created |
| * |
| * @return the size requirements for this <code>BoxView</code> along |
| * the specified axis |
| */ |
| protected SizeRequirements calculateMinorAxisRequirements(int axis, |
| SizeRequirements r) |
| { |
| SizeRequirements res = r; |
| if (res == null) |
| res = new SizeRequirements(); |
| res.minimum = (int) layoutPool.getMinimumSpan(axis); |
| res.preferred = Math.max(res.minimum, |
| (int) layoutPool.getPreferredSpan(axis)); |
| res.maximum = Integer.MAX_VALUE; |
| res.alignment = 0.5F; |
| return res; |
| } |
| } |