Skip to content

Commit

Permalink
Adding new optional parameter repeat_headings for FPDF.table() (#1153)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucas-C committed May 3, 2024
1 parent 23d76b1 commit d7d0ab2
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 3 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Expand Up @@ -18,7 +18,7 @@ This can also be enabled programmatically with `warnings.simplefilter('default',

## [2.7.9] - Not released yet
### Added
* fix bug causing a warning message in Acrobat
* new optional parameter `repeat_headings` for [`FPDF.table()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.table) that indicates whether to print table headings on every page
* support for overriding paragraph direction on bidirectional text
* new optional `li_prefix_color` parameter for [`FPDF.write_html()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write_html)
* support for `start` & `type` attributes of `<ol>` tags, and `type` attribute of `<ul>` tags, when using [`FPDF.write_html()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write_html)
Expand All @@ -27,6 +27,7 @@ This can also be enabled programmatically with `warnings.simplefilter('default',
* [`FPDF.write_html()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write_html) now honors `line-height` attributes on `<ol>` & `<li>` elements, or the same CSS property in `style` attributes on those tags
* allow to define custom `cell_fill_mode` logic for tables: [_Set cells background_ - documentation section](https://py-pdf.github.io/fpdf2/Tables.html#set-cells-background). Also added 2 new values: `TableCellFillMode.EVEN_ROWS` & `TableCellFillMode.EVEN_COLUMNS`: [documentation](https://py-pdf.github.io/fpdf2/fpdf/enums.html#fpdf.enums.TableCellFillMode)
### Fixed
* a bug when rendering vector images with dashed lines that caused a warning message in Adobe Acrobat Reader
* ordering RTL fragments on bidirectional texts
* fixed type hint of member `level` in class [`OutlineSection`](https://py-pdf.github.io/fpdf2/fpdf/outline.html#fpdf.outline.OutlineSection) from `str` to `int`.
* SVG clipping paths being incorrectly painted - _cf._ [issue #1147](https://github.com/py-pdf/fpdf2/issues/1147)]
Expand Down
13 changes: 13 additions & 0 deletions docs/Tables.md
Expand Up @@ -134,12 +134,25 @@ with pdf.table(line_height=2.5 * pdf.font_size) as table:

## Disable table headings

By default, `fpdf2` considers that the first row of tables contains its headings.
This can however be disabled:

```python
...
with pdf.table(first_row_as_headings=False) as table:
...
```

The **repetition** of table headings on every page can also be disabled:

```python
...
with pdf.table(repeat_headings=1) as table:
...
```

`"ON_TOP_OF_EVERY_PAGE"` is an equivalent valid value for `repeat_headings`.

## Style table headings

```python
Expand Down
10 changes: 10 additions & 0 deletions fpdf/enums.py
Expand Up @@ -354,6 +354,16 @@ class TableSpan(CoerciveEnum):
"Mark this cell as a continuation of the previous column"


class TableHeadingsDisplay(CoerciveIntEnum):
"Defines how the table headings should be displayed"

NONE = 0
"Only render the table headings at the beginning of the table"

ON_TOP_OF_EVERY_PAGE = 1
"When a page break occurs, repeat the table headings at the top of every table fragment"


class RenderStyle(CoerciveEnum):
"Defines how to render shapes"

Expand Down
3 changes: 2 additions & 1 deletion fpdf/fpdf.py
Expand Up @@ -618,7 +618,7 @@ def set_text_shaping(
return
#
# Features must be a dictionary contaning opentype features and a boolean flag
# stating wether the feature should be enabled or disabled.
# stating whether the feature should be enabled or disabled.
#
# e.g. features={"liga": True, "kern": False}
#
Expand Down Expand Up @@ -4998,6 +4998,7 @@ def table(self, *args, **kwargs):
num_heading_rows (number): optional. Sets the number of heading rows, default value is 1. If this value is not 1,
first_row_as_headings needs to be True if num_heading_rows>1 and False if num_heading_rows=0. For backwards compatibility,
first_row_as_headings is used in case num_heading_rows is 1.
repeat_headings (fpdf.enums.TableHeadingsDisplay): optional, indicates whether to print table headings on every page, default to 1.
"""
table = Table(self, *args, **kwargs)
yield table
Expand Down
9 changes: 8 additions & 1 deletion fpdf/table.py
Expand Up @@ -7,6 +7,7 @@
MethodReturnValue,
TableBordersLayout,
TableCellFillMode,
TableHeadingsDisplay,
WrapMode,
VAlign,
TableSpan,
Expand Down Expand Up @@ -47,6 +48,7 @@ def __init__(
padding=None,
outer_border_width=None,
num_heading_rows=1,
repeat_headings=1,
):
"""
Args:
Expand Down Expand Up @@ -79,6 +81,7 @@ def __init__(
num_heading_rows (number): optional. Sets the number of heading rows, default value is 1. If this value is not 1,
first_row_as_headings needs to be True if num_heading_rows>1 and False if num_heading_rows=0. For backwards compatibility,
first_row_as_headings is used in case num_heading_rows is 1.
repeat_headings (fpdf.enums.TableHeadingsDisplay): optional, indicates whether to print table headings on every page, default to 1.
"""
self._fpdf = fpdf
self._align = align
Expand All @@ -98,6 +101,7 @@ def __init__(
self._width = fpdf.epw if width is None else width
self._wrapmode = wrapmode
self._num_heading_rows = num_heading_rows
self._repeat_headings = TableHeadingsDisplay.coerce(repeat_headings)
self._initial_style = None
self.rows = []

Expand Down Expand Up @@ -211,13 +215,16 @@ def render(self):
row_info = list(self._process_rowpans_entries())

# actually render the cells
repeat_headings = (
self._repeat_headings is TableHeadingsDisplay.ON_TOP_OF_EVERY_PAGE
)
self._fpdf.y += self._outer_border_margin[1]
for i, row in enumerate(self.rows):
# pylint: disable=protected-access
page_break = self._fpdf._perform_page_break_if_need_be(
row_info[i].pagebreak_height
)
if page_break and i >= self._num_heading_rows:
if page_break and repeat_headings and i >= self._num_heading_rows:
# repeat headings on top:
self._fpdf.y += self._outer_border_margin[1]
for row_idx in range(self._num_heading_rows):
Expand Down
Binary file not shown.
27 changes: 27 additions & 0 deletions test/table/test_table.py
Expand Up @@ -352,6 +352,33 @@ def test_table_with_single_top_line_layout_and_page_break(tmp_path): # PR #912
)


def test_table_with_page_break_and_headings_repeated(tmp_path): # issue 1151
pdf = FPDF()
pdf.add_page()
pdf.set_font("Times", size=16)
pdf.cell(text="repeat_headings=1:", new_y="NEXT")
with pdf.table(
MULTILINE_TABLE_DATA,
repeat_headings=1,
):
pass
pdf.cell(text='repeat_headings="NONE":', new_y="NEXT")
with pdf.table(
MULTILINE_TABLE_DATA,
repeat_headings="NONE",
):
pass
pdf.cell(text='repeat_headings="ON_TOP_OF_EVERY_PAGE":', new_y="NEXT")
with pdf.table(
MULTILINE_TABLE_DATA,
repeat_headings="ON_TOP_OF_EVERY_PAGE",
):
pass
assert_pdf_equal(
pdf, HERE / "table_with_page_break_and_headings_repeated.pdf", tmp_path
)


def test_table_align(tmp_path):
pdf = FPDF()
pdf.add_page()
Expand Down

0 comments on commit d7d0ab2

Please sign in to comment.