private BalancingResult applyBestResult() { final float hCenter = horCenter(); List<Element> elements = sequence.getElements(); setColumn((float) bestResult.leftColumnHeight, hCenter, true, true, singleColumnRect, leftCTB); setColumn( (float) bestResult.rightColumnHeight, hCenter, false, false, singleColumnRect, rightCTB); if (b.drawBorders) { b.getCanvasBuilder().drawGrayRectangle(leftCTB.getSimpleColumnRectangle(), BaseColor.RED); b.getCanvasBuilder().drawGrayRectangle(rightCTB.getSimpleColumnRectangle(), BaseColor.GREEN); } leftCTB.clearContent(); rightCTB.clearContent(); final DirectContentAdder.Result addResult = new DirectContentAdder(leftCTB) .setStartWith(initialLeftCTB) .setStartAtIndex(startAtElement) .setSwitchToRightCTB(rightCTB) .setSimulate(false) .go(); float yLine = Math.min(leftCTB.getYLine(), rightCTB.getYLine()); final BalancingResult r; if (addResult.hasContentLeft(elements.size())) { final ColumnTextBuilder contentCopy = addResult.contentLeft == null ? null : b.newColumnTextBuilder().setACopy(addResult.contentLeft); r = startWithANewPage(contentCopy, addResult.index); } else { r = new BalancingResult(yLine); // if(updateAfterRun != null){ // updateAfterRun.growBottom(origRectangle.getTop() - yLine); // } } if (updateAfterRun != null) { updateAfterRun.setSimpleColumn( b.reuseRectangleBuilder(new Rectangle(origRectangle.get())) .setTop(yLine) .setBottom(b.getDocument().bottom()) .get()); } return r; }
private ColumnTextBuilder setColumn( float height, float horCenter, boolean isLeft, boolean simulate, RectangleBuilder singleColumnRect, ColumnTextBuilder ctb) { // new RectangleBuilder(). final RectangleBuilder rect = b.newCopyRectangleBuilder(origRectangle.get()) .setBottom(singleColumnRect.getTop() - height); if (isLeft) { rect.setRight(horCenter); } else { rect.setLeft(horCenter); } applyPadding(rect, isLeft); logger.debug("setting column to: {}", rect); ctb.setSimpleColumn(rect.get()); return ctb; }
private float calcReferenceHeight(float hCenter) { float yBefore = origRectangle.getTop(); ColumnTextBuilder tempCtb = b.newColumnTextBuilder(); singleColumnRect.copyPositionsFrom(origRectangle); singleColumnRect.setBottom(-100000f); singleColumnRect.setRight(hCenter); applyPadding(singleColumnRect, true); tempCtb.setSimpleColumn(singleColumnRect.get()); final DirectContentAdder adder = new DirectContentAdder(tempCtb); adder .setStartWith(initialLeftCTB) .setStartAtIndex(startAtElement) .setSimulate(true) .setHeights(true) .go(); sequence.initialContentHeight = adder.startContentHeight; float yAfter = tempCtb.getYLine(); return (yBefore - yAfter); }
private BalancingResult startWithANewPage(ColumnTextBuilder content, int startAt) { //noinspection SimplifiableConditionalExpression logger.debug( "starting with a new page, content: {}, startAt: {}", content == null ? false : content.hasMoreText(), startAt); final RectangleBuilder rect = b.reuseRectangleBuilder(origRectangle.get()) .setTop(b.getDocument().top()) .setBottom(b.getDocument().bottom()); b.getDocument().newPage(); return new BalancedColumnsBuilder(content, startAt, rect.get(), b).setSequence(sequence).go(); }
public boolean fits() { final boolean simulate = true; // try adding into a single infinite column to calc height ColumnTextBuilder ctb = b.reuseColumnTextBuilder(); b.reuseRectangleBuilder(tempR).copyPositionsFrom(rectangle); tempR.setBottom(-10000f); tempR.setRight(horCenter()); applyPadding(tempR, true); ctb.setSimpleColumn(tempR); float yBefore = ctb.getYLine(); contentAdder.add(ctb, simulate); int status = ctb.go(simulate); if (ColumnText.hasMoreText(status)) { return false; } float yAfter = ctb.getYLine(); final float height = yBefore - yAfter; logger.trace("height: {}", height); // if(height > rectangle.getHeight()) { // return false; // } // now try adding into two actual columns final float columnHeight = height / 2 + additionalSpaceForColumn; if (!addToTwoColumns(simulate, columnHeight)) { return false; } addToTwoColumns(false, columnHeight); return true; }
public TwoColumnsSectionBuilder addToDocument(float pageTop, float pageBottom) { Document document = b.getDocument(); int pageCount = 0; for (; !tryAdding() && pageCount < MAX_PAGE_COUNT; pageCount++) { document.newPage(); newPage(pageTop, pageBottom).tryAdding(); } if (pageCount == MAX_PAGE_COUNT) { throw new IllegalStateException("two columns took more than " + MAX_PAGE_COUNT + " pages"); } return this; }
private boolean addToTwoColumns(boolean simulate, float height) { ColumnTextBuilder ctb; int status; ctb = b.reuseColumnTextBuilder(); b.reuseRectangleBuilder(tempR).copyPositionsFrom(rectangle); final float horCenter = horCenter(); setColumn(height, horCenter, true, ctb, simulate); contentAdder.add(ctb, simulate); status = ctb.go(simulate); yLine = ctb.getYLine(); if (!ColumnText.hasMoreText(status) && simulate) { return true; } setColumn(height, horCenter, false, ctb, simulate); status = ctb.go(simulate); yLine = Math.min(yLine, ctb.getYLine()); // right column may not fit the rect, check if does fit the page if (simulate) { if (yLine < rectangle.getBottom()) { return false; } } return !ColumnText.hasMoreText(status); }
private void setColumn( float height, float horCenter, boolean left, ColumnTextBuilder ctb, boolean simulate) { b.reuseRectangleBuilder(tempR).copyPositionsFrom(rectangle); tempR.setBottom(tempR.getTop() - height); if (left) { tempR.setRight(horCenter); } else { tempR.setLeft(horCenter); tempR.setBottom(-10000f); } applyPadding(tempR, left); logger.debug("setting column to: {}", tempR); ctb.setSimpleColumn(tempR); }
private void considerAddingToRight(int startAt, boolean hasNotFlushedText) { logger.trace( "adding to right, i: {}, leftHeight: {}, leftSplit: {}", startAt, currentLeftResult.leftColumnHeight, currentLeftResult.leftElementSplitHeight); // copy content from the left rightCTB.setACopy(leftCTB).setYLine(leftCTB.getTop()); if (!hasNotFlushedText && sequence.isSpace(startAt)) { startAt++; } // we can flush what's left from the previous column if (rightCTB.hasMoreText()) { rightCTB.go(true); } currentRightResult.copyFrom(currentLeftResult); // copied from left method int i; List<Element> elements = sequence.getElements(); final DirectContentAdder.Result quickResult = new DirectContentAdder(rightCTB) .setStartWith(leftCTB) .setStartAtIndex(startAt) .setQuickHeight(leftCTB.getCurrentHeight()) .setSimulate(true) .go(); i = quickResult.index; int elementsAdded = quickResult.contentLeft == null ? i : i - 1; bestResult.assignIfWorseThan( currentRightResult .setElementsAddedCount(elementsAdded) // todo!!! .setRightElementSplitHeight(0, 0) .setRightColumnHeight(rightCTB.getCurrentHeight()) .setPageSplit(elementsAdded, quickResult.hasContentLeft(elements.size()))); boolean pageOverFlow = false; if (quickResult.contentLeft != null) { rightCTB.copyContentFrom(quickResult.contentLeft); AtomicIncreaseResult lastResult = iterateOnRight( i - 1, currentRightResult, rightCTB.getTop(), rightCTB.newAtomicIteratorFor()); if (lastResult.type == ColumnTextBuilder.GrowthResultType.PAGE_OVERFLOW) { pageOverFlow = true; } } if (i == elements.size()) { bestResult.assignIfWorseThan( currentRightResult .setRightElementSplitHeight(0, 0) .setRightColumnHeight(rightCTB.getCurrentHeight()) .setElementsAddedCount(i) .setPageSplit(i, rightCTB.hasMoreText())); } if (pageOverFlow) return; elementsCycle: for (; i < elements.size(); i++) { Element el = elements.get(i); final SplitResult currentResult = currentRightResult; setFullAddedElementsStateRight(currentResult, i, rightCTB.getCurrentHeight()); currentResult.setPageSplit(true); // temporary pessimism if (el instanceof SpaceElement) { // todo extract method SpaceElement space = (SpaceElement) el; bestResult.assignIfWorseThan(currentResult.setElementsAddedCount(i).setPageSplit(i, false)); if (space.fits(rightCTB, origRectangle.getBottom())) { space.add(rightCTB, true); } else { if (rightCTB.getSimpleColumnRectangle().getBottom() - space.getHeight() < b.getDocument().bottom()) { break; } rightCTB.growBottom(space.getHeight()).setYLine(rightCTB.getYLine() - space.getHeight()); } } else { float elementTop = rightCTB.getYLine(); final Iterator<AtomicIncreaseResult> iterator = rightCTB.newAtomicIteratorFor(el); AtomicIncreaseResult lastResult = iterateOnRight(i, currentResult, elementTop, iterator); if (lastResult.type == ColumnTextBuilder.GrowthResultType.PAGE_OVERFLOW) { break; } } // element is fully added here currentResult .setRightColumnHeight(rightCTB.getCurrentHeight()) .setRightElementSplitHeight(0, 0); bestResult.assignIfWorseThan(currentResult); } }
private BalancingResult _go() { if (b.drawBorders) { b.getCanvasBuilder().drawGrayRectangle(origRectangle.get(), BaseColor.LIGHT_GRAY); } currentLeftResult.totalElementCount = currentRightResult.totalElementCount = bestResult.totalElementCount = sequence.size(); // try adding into a single infinite column to calc height final float hCenter = horCenter(); referenceHeight = calcReferenceHeight(hCenter); currentLeftResult.referenceHeight = currentRightResult.referenceHeight = bestResult.referenceHeight = referenceHeight; leftCTB = setColumn( (float) referenceHeight, hCenter, true, true, singleColumnRect, b.newColumnTextBuilder()); rightCTB = setColumn( (float) referenceHeight, hCenter, false, true, singleColumnRect, b.newColumnTextBuilder()); minimalLeftColumnHeight = MINIMAL_HEIGHT_COEFFICIENT * referenceHeight / 2; int i; List<Element> elements = sequence.getElements(); final DirectContentAdder.Result quickResult = new DirectContentAdder(leftCTB) .setStartWith(initialLeftCTB) .setStartAtIndex(startAtElement) .setQuickHeight(minimalLeftColumnHeight) .setSimulate(true) .go(); i = quickResult.index; bestResult.assignIfWorseThan( currentLeftResult .setElementsAddedCount(i) .setLeftElementSplitHeight(0, 0) .setLeftColumnHeight(leftCTB.getCurrentHeight()) .setPageSplit(i, quickResult.hasContentLeft(elements.size()))); boolean pageOverFlow = false; // the only situation possible is the content left from initialContent if (quickResult.contentLeft != null) { leftCTB.copyContentFrom(quickResult.contentLeft); pageOverFlow = iterateOnLeft( leftCTB.newAtomicIteratorFor(), i - 1, currentLeftResult, leftCTB.getTop(), sequence.initialContentHeight); } if (i == elements.size()) { bestResult.assignIfWorseThan( currentLeftResult .setLeftElementSplitHeight(0, 0) .setLeftColumnHeight(leftCTB.getCurrentHeight()) .setElementsAddedCount(i) .setPageSplit(i, leftCTB.hasMoreText())); } if (pageOverFlow) { return applyBestResult(); } elementsCycle: for (; i < elements.size(); i++) { Element el = elements.get(i); final SplitResult currentResult = currentLeftResult; currentResult .setLeftElementSplitHeight(0, 0) .setElementsAddedCount(i) .setLeftColumnHeight(leftCTB.getCurrentHeight()); considerAddingOnRightAtWholeElement(i); if (el instanceof SpaceElement) { SpaceElement space = (SpaceElement) el; currentResult.setElementsAddedCount(i); considerAddingToRight(i + 1, false); if (space.fits(leftCTB, origRectangle.getBottom())) { space.add(leftCTB, true); } else { if (leftCTB.getSimpleColumnRectangle().getBottom() - space.getHeight() < b.getDocument().bottom()) { break; } leftCTB.growBottom(space.getHeight()).setYLine(leftCTB.getYLine() - space.getHeight()); } } else { float elementTop = leftCTB.getYLine(); final Iterator<AtomicIncreaseResult> iterator = leftCTB.newAtomicIteratorFor(el); if (iterateOnLeft(iterator, i, currentResult, elementTop, sequence.getHeight(i))) { break elementsCycle; } // leftCTB.restoreState(); } currentResult.setLeftColumnHeight(leftCTB.getCurrentHeight()).setElementsAddedCount(i + 1); } considerAddingOnRightAtWholeElement(i); // here we have bestResult, so let's add our content with no simulation! // setColumn(bestResult, b.newColumnTextBuilder()) return applyBestResult(); }