v0.6.0 BigUpdate
Example document / build (push) Has been cancelled
Python application / build (push) Has been cancelled

This commit is contained in:
Igor20264
2026-10-20 11:38:06 +03:00
parent daa84f8bce
commit 8223e0ac14
77 changed files with 12158 additions and 117 deletions
+125
View File
@@ -39,6 +39,28 @@ DOCX_SAVE_FILTER_SPECS = {
}
MAX_PASSES = 20
# Stop if pagination never settles (each pass is one split, budget can grow).
PASS_SAFETY_CAP = 200
def continuation_pass_limit(object_count, splits_done=0):
"""10 + (tables + listings) + 1 per split already made.
One pass performs one split.
"""
try:
count = int(object_count)
except (TypeError, ValueError):
count = 0
try:
done = int(splits_done)
except (TypeError, ValueError):
done = 0
if count < 0:
count = 0
if done < 0:
done = 0
return 10 + count + done
# UNO enum numeric values (``from com.sun.star.*`` is unavailable in some LO/OO Pythons).
BREAK_NONE = 0
@@ -162,6 +184,109 @@ def find_page_break_row(page_numbers):
return None
def resume_page_before_cut(cut_page):
"""Page to scan from after a split: the page before the cut, not page 1.
Rows that move to the continuation start on ``cut_page``. Only that page
and the pages after it can shift, so the next pass starts at ``cut_page - 1``.
"""
try:
page = int(cut_page)
except (TypeError, ValueError):
return 1
if page <= 2:
return 1
return page - 1
def locate_break_row(n_rows, page_at, min_page=1):
"""Return ``(break_row_1based, cut_page)`` or ``(None, None)``.
``page_at(row_1based)`` returns a page number or None. Pages are treated as
non-decreasing. The search skips a table that ends before ``min_page`` and
binary-searches the first later jump, instead of reading every row from
the start. A failed probe falls back to a forward scan.
"""
try:
n_rows = int(n_rows)
except (TypeError, ValueError):
return None, None
try:
min_page = int(min_page)
except (TypeError, ValueError):
min_page = 1
if n_rows < 2:
return None, None
if min_page < 1:
min_page = 1
cache = {}
def probe(row):
if row in cache:
return cache[row]
try:
page = page_at(row)
except Exception:
page = None
if page is not None:
try:
page = int(page)
except (TypeError, ValueError):
page = None
cache[row] = page
return page
first = probe(1)
last = probe(n_rows)
if first is None or last is None:
return _linear_break_row(n_rows, probe, min_page)
if last < min_page or first == last:
return None, None
threshold = (first + 1) if first >= min_page else min_page
row = _first_row_at_or_after(n_rows, probe, threshold)
if row is None or row <= 1:
return _linear_break_row(n_rows, probe, min_page)
cut = probe(row)
prev = probe(row - 1)
if cut is None or prev is None or prev >= cut or cut < threshold:
return _linear_break_row(n_rows, probe, min_page)
return row, cut
def _first_row_at_or_after(n_rows, probe, threshold):
lo = 1
hi = n_rows
found = None
while lo <= hi:
mid = (lo + hi) // 2
page = probe(mid)
if page is None:
return None
if page >= threshold:
found = mid
hi = mid - 1
else:
lo = mid + 1
return found
def _linear_break_row(n_rows, probe, min_page):
prev = probe(1)
if prev is None:
return None, None
row = 2
while row <= n_rows:
page = probe(row)
if page is None:
page = prev
if page > prev and page >= min_page:
return row, page
prev = page
row += 1
return None, None
def is_orphan_header_break(break_at, had_header):
return bool(had_header and break_at == 2)