Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding new optional parameter repeat_headings for FPDF.table() #1153

Merged
merged 2 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading