landings
landings

Reputation: 770

How can I undo paragraph addings?

I am using iText 7.2.1.

I have multiple long articles of various lengths. What I need to do is:

  1. Pick one article in the candidate set and add it into my document. The newly added article will be right following the previous one. There may be automatic page changing.

  2. Check if this newly added article meets some criterion. (For example: Check if its ending line is at the right position of a page)

  3. If not, undo this adding, and try next article in the candidate set.

There seems no "undo"s for a Document. So I'm wondering if I can duplicate my current document to test. Or is there any other way to test before adding?

Upvotes: 0

Views: 134

Answers (1)

Uladzimir Asipchuk
Uladzimir Asipchuk

Reputation: 2458

In the question's comments section the idea of relayout was suggested, however, it hasn't been demonstrated how it can be efficiently applied to your case. This is how I see your demands:

  1. You want to consider paragraphs one by one. In the rest of the answer I will call these parahraphs "candidates".
  2. For each of the candidates you want to layout it and check whether it meets some of your criteria.
  3. If the anwer is yes, then you want to add this paragraph to the document.
  4. In any case, regardless whether the candidate was added or not, you want to proceed with another candidate.

I want to explicitly mention the word "layout" rather than "add": in the solution proposed below I will try layouting candidates without actually adding them to the document. Once the candidate is layouted, you can check it against your criteria and if it meets them, then the candidate should be added.

Below is the main part of the code. As you can see, here I do the following: until the requested number of paragraphs is added, I generate paragraphs of random size and check with the help of isParagraphAccepted whether they are accepted or not. If true, then I add them to the document and reduce the number of paragraphs to be added.

    PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName));
    Document doc = new Document(pdfDoc);

    RootRenderer rootRenderer = doc.getRenderer();
    Rectangle defaultArea = pdfDoc.getDefaultPageSize();
    
    int paragraphsToAddCount = 10;

    LoremIpsum lorem = LoremIpsum.getInstance();
    int minLoremCount = 25;
    int maxLoremCount = 50;

    int counter = 0;
    while (paragraphsToAddCount > 0) {
        Paragraph p = new Paragraph(lorem.getParagraphs(minLoremCount, maxLoremCount));
        if (isParagraphAccepted(p, rootRenderer, defaultArea)) {
            doc.add(p);
            paragraphsToAddCount--;
        }
        counter++;
    }

    System.out.println("We have considered " + counter + " paragraphs.");
    doc.close();

The magic, however, is done in isParagraphAccepted, so let's take a look:

    boolean isParagraphAccepted(Paragraph p, RootRenderer rootRenderer, Rectangle defaultArea) {
    Rectangle currentArea = null == rootRenderer.getCurrentArea()
            ? defaultArea
            : rootRenderer.getCurrentArea().getBBox();

    IRenderer paragraphRenderer = p.createRendererSubTree().setParent(rootRenderer);
    LayoutResult layoutResult = paragraphRenderer.layout(new LayoutContext(new LayoutArea(0, currentArea)));
    while (LayoutResult.FULL != layoutResult.getStatus()) {
        currentArea = defaultArea;
        paragraphRenderer = layoutResult.getOverflowRenderer();
        layoutResult = paragraphRenderer.layout(new LayoutContext(new LayoutArea(0, currentArea)));
    }

    // checking against some criteria
    return layoutResult.getOccupiedArea().getBBox().getHeight() > 500;
}

Basically, in this method the following is done: the pararaph gets layouted page after page until it's finally fully layouted and then I check the area it occupies on the last page against some criteria.

Upvotes: 3

Related Questions