871 lines · 32.1 KB · Java
RawDownload
         *   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);        }         // 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) {        }    }  }

Lines 501–871 of 871. Previous lines