vandeseer / easytable

Small table drawing library built upon Apache PDFBox

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

RuntimeException when getting the height of a complicated table

Thejipppp opened this issue Β· comments

Hi

Please don't hate me πŸ˜‹
The idea of making a general splitter is riping in my head, but it needs some time. In the meanwhile, I found another bug.
I'm trying to split my own tables over different pages with A LOT of extra code to do that, but now I found a table that crashes when you ask for it's height. Without height, I can't split.
Maybe interesting, the height is on purpose bigger than one page, that is why Lorem Ipsum is fed in πŸ˜„

The code crashes here, in Row.getHeight()
image

Structure of the table looks like this, each color is a row.
image

In words, it looks like this

new row
	text cell, rowSpan: 1, colSpan: 1
	text cell, rowSpan: 5, colSpan: 1
	text cell, rowSpan: 2, colSpan: 2
new row
	text cell, rowSpan: 4, colSpan: 1
new row
	text cell, rowSpan: 1, colSpan: 2
new row
	text cell, rowSpan: 1, colSpan: 2
new row
	text cell, rowSpan: 1, colSpan: 2

or what you would like more, in code:

        String text1 = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus convallis molestie arcu, quis malesuada orci venenatis sit amet. Sed ligula dui, mollis in nulla ac, fermentum cursus orci. Nunc sollicitudin sagittis arcu, ornare ornare diam malesuada quis. Etiam viverra tellus ac faucibus pellentesque. Pellentesque elit est, tincidunt eget porta non, rutrum non tortor. Sed mattis est sem, id tristique est consectetur in. Integer egestas, risus in laoreet malesuada, ex odio congue felis, ac elementum nisl neque quis enim. Integer nunc enim, rhoncus sed rhoncus eu, pharetra ut odio. Sed velit arcu, ultricies ut egestas vulputate, finibus in sem.";
		String text2 = "Duis nec augue felis. Sed blandit vel ex vel euismod. Integer dictum velit sit amet dui imperdiet dignissim. Donec sollicitudin mauris sit amet consequat tincidunt. Maecenas at nibh dapibus, sodales massa quis, porta sem. Vivamus vitae molestie velit. Integer ac lectus eleifend quam consectetur aliquet. Sed et augue eu purus euismod egestas. Duis tincidunt libero eget ligula scelerisque, quis dignissim lorem porta. Cras facilisis ex mi.";
		String text3 = "Vestibulum facilisis dictum mi. Sed et faucibus dui. Sed eu elit iaculis, pulvinar mauris sed, interdum arcu. Aenean condimentum efficitur quam id feugiat. Vestibulum dolor purus, pellentesque et ante vel, tempus fermentum nulla. Sed eu lectus quam. Etiam at libero sit amet enim venenatis molestie eu quis nisi. Interdum et malesuada fames ac ante ipsum primis in faucibus. Etiam ac enim metus. Donec sit amet lobortis arcu.";
		String text4 = "Aenean commodo id lectus a condimentum. Sed quis porttitor justo. Cras bibendum, leo quis facilisis auctor, diam ante eleifend libero, bibendum scelerisque arcu risus ultrices mauris. Cras cursus nisi ac posuere feugiat. Aenean convallis dui sed metus pellentesque accumsan. Mauris sollicitudin nunc at massa venenatis mollis. In cursus arcu sed odio placerat, ac sodales felis vulputate. Aliquam dui diam, tincidunt quis lacinia a, rhoncus et mauris. Vestibulum ex velit, ornare a mattis id, congue a ligula. Maecenas ac est justo. Donec volutpat pharetra molestie. Sed tempor, lectus eget rutrum fringilla, lacus arcu malesuada metus, eget pharetra nulla purus quis risus. Pellentesque feugiat, lacus nec vehicula posuere, ante risus ultrices eros, et sagittis ipsum lorem quis ligula. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla eget tellus diam. Curabitur eget condimentum justo.";
		Table table = Table.builder().addColumnsOfWidth(110f, 137.5f, 33f, 270f).borderColor(BLACK).fontSize(8)
				.font(HELVETICA_BOLD_OBLIQUE)
				.addRow(Row.builder().backgroundColor(GRAY).textColor(BLACK).horizontalAlignment(CENTER)
					.add(TextCell.builder().borderWidth(1).text("xxx").rowSpan(1).colSpan(1).build())
					.add(TextCell.builder().borderWidth(1).text("xxx").rowSpan(5).colSpan(1).build())
					.add(TextCell.builder().borderWidth(1).text(text1).rowSpan(2).colSpan(2).build())
					.build()
				)
				.addRow(Row.builder().backgroundColor(GRAY).textColor(BLACK).horizontalAlignment(CENTER)
					.add(TextCell.builder().borderWidth(1).text("xxx").rowSpan(4).colSpan(1).build())
					.build()
				)
				.addRow(Row.builder().backgroundColor(GRAY).textColor(BLACK).horizontalAlignment(CENTER)
					.add(TextCell.builder().borderWidth(1).text(text2).rowSpan(1).colSpan(2).build())
					.build()
				)
				.addRow(Row.builder().backgroundColor(GRAY).textColor(BLACK).horizontalAlignment(CENTER)
					.add(TextCell.builder().borderWidth(1).text(text3).rowSpan(1).colSpan(2).build())
					.build()
				)
				.addRow(Row.builder().backgroundColor(GRAY).textColor(BLACK).horizontalAlignment(CENTER)
					.add(TextCell.builder().borderWidth(1).text(text4).rowSpan(1).colSpan(2).build())
					.build()
				)
				.build();
				
		return table;

I see that the problem is the filter, and row 2 doesn't have a cell with a row span of 1. But I think it's a valid table though?

Changing it to this makes a stackoverflow, so that's also no solution πŸ˜„
image

Wow. With implementing row spanning I really opened the Pandora's box... πŸ˜„

Interesting indeed. I will have a look. But no idea if I am able and willing to fix this πŸ˜‰

Regarding your picture of the table where each row is colored: There is indeed a difficulty with calculating the height of the yellow part in line 2:

image

What height should it get? The base height of the regular cells of row 2? But what is it if there is not at least one regular cell in there (i.e. a cell with row span == 1)?

One option would be to set it to some (configurable?) default height like so:

public float getHeight() {
    if (table == null) {
        throw new TableNotYetBuiltException();
    }

    if (height == null) {
        this.height = getCells().stream()
                .filter(cell -> cell.getRowSpan() == 1)
                .map(AbstractCell::getHeight)
                .max(naturalOrder())
                .orElse(DEFAULT_HEIGHT); // or maybe defaultRowHeight which can be set explicitly ...
    }

    return height;
}

I am not quite sure yet though if there is any bigger drawback then but can it be worse than a RuntimeException? πŸ€” πŸ˜„

Fixed in v0.8.2 using the approach described above.