v0.6.0 BigUpdate
This commit is contained in:
@@ -11,7 +11,8 @@ import sys
|
||||
import time
|
||||
|
||||
from uno_helpers import (
|
||||
MAX_PASSES,
|
||||
PASS_SAFETY_CAP,
|
||||
continuation_pass_limit,
|
||||
CaptionInfo,
|
||||
as_unicode,
|
||||
caption_style_name,
|
||||
@@ -22,6 +23,8 @@ from uno_helpers import (
|
||||
BREAK_PAGE_BEFORE,
|
||||
CONTROL_PARAGRAPH_BREAK,
|
||||
find_page_break_row,
|
||||
locate_break_row,
|
||||
resume_page_before_cut,
|
||||
is_caption_orphaned,
|
||||
is_orphan_header_break,
|
||||
parse_caption_text,
|
||||
@@ -489,6 +492,20 @@ def _caption_for_split(doc, table):
|
||||
)
|
||||
|
||||
|
||||
def _count_split_targets(doc, tables, listings):
|
||||
"""Captioned tables and listings this pass is allowed to split."""
|
||||
found = 0
|
||||
for table in _body_tables(doc):
|
||||
caption = _caption_before_table(doc, table)
|
||||
if caption is None:
|
||||
continue
|
||||
if caption.kind == "table" and tables:
|
||||
found += 1
|
||||
elif caption.kind == "listing" and listings:
|
||||
found += 1
|
||||
return found
|
||||
|
||||
|
||||
def _caption_page_before_table(doc, table):
|
||||
try:
|
||||
anchor = _uno_call(table, "Anchor")
|
||||
@@ -506,6 +523,26 @@ def _caption_page_before_table(doc, table):
|
||||
return None
|
||||
|
||||
|
||||
def _page_at_row(doc, table, row_1based):
|
||||
"""Page number of one row, or None. Rows are 1-based, UNO cells are 0-based."""
|
||||
row = int(row_1based) - 1
|
||||
if row < 0:
|
||||
return None
|
||||
try:
|
||||
ncols = int(table.getColumns().getCount())
|
||||
except Exception:
|
||||
ncols = 1
|
||||
for col in range(max(1, ncols)):
|
||||
try:
|
||||
cell = table.getCellByPosition(col, row)
|
||||
page = _page_at_range(doc, _uno_call(cell, "Start"))
|
||||
if page is not None:
|
||||
return int(page)
|
||||
except Exception:
|
||||
continue
|
||||
return None
|
||||
|
||||
|
||||
def _row_page_numbers(doc, table):
|
||||
pages = []
|
||||
try:
|
||||
@@ -1049,10 +1086,16 @@ def _copy_header_to_continuation(first_table, cont_table):
|
||||
pass
|
||||
|
||||
|
||||
def _fix_pass(uno, ctx, doc, tables, listings, repeat_header, details):
|
||||
def _fix_pass(uno, ctx, doc, tables, listings, repeat_header, details, start_page=1):
|
||||
"""Split the first crossing table. Returns (made, cut_page)."""
|
||||
made = 0
|
||||
cut_page = None
|
||||
try:
|
||||
start_page = int(start_page)
|
||||
except (TypeError, ValueError):
|
||||
start_page = 1
|
||||
body_tables = _body_tables(doc)
|
||||
for table in reversed(body_tables):
|
||||
for table in body_tables:
|
||||
caption = _caption_for_split(doc, table)
|
||||
if caption is None:
|
||||
continue
|
||||
@@ -1061,9 +1104,18 @@ def _fix_pass(uno, ctx, doc, tables, listings, repeat_header, details):
|
||||
if caption.kind == "listing" and not listings:
|
||||
continue
|
||||
|
||||
pages = _row_page_numbers(doc, table)
|
||||
if caption.kind == "table" and pages and not caption.is_continuation:
|
||||
if is_caption_orphaned(_caption_page_before_table(doc, table), pages[0]):
|
||||
try:
|
||||
row_count = int(table.getRows().getCount())
|
||||
except Exception:
|
||||
continue
|
||||
if start_page > 1 and row_count > 0:
|
||||
last_page = _page_at_row(doc, table, row_count)
|
||||
if last_page is not None and last_page < start_page:
|
||||
continue
|
||||
|
||||
first_page = _page_at_row(doc, table, 1) if row_count else None
|
||||
if caption.kind == "table" and first_page is not None and not caption.is_continuation:
|
||||
if is_caption_orphaned(_caption_page_before_table(doc, table), first_page):
|
||||
try:
|
||||
if _page_break_before_table_caption(doc, table):
|
||||
details.append(
|
||||
@@ -1082,10 +1134,14 @@ def _fix_pass(uno, ctx, doc, tables, listings, repeat_header, details):
|
||||
details.append("skip: orphan-caption page break: {0}".format(exc))
|
||||
continue
|
||||
|
||||
break_at = find_page_break_row(pages)
|
||||
break_at, cut_page = locate_break_row(
|
||||
row_count,
|
||||
lambda row, current=table: _page_at_row(doc, current, row),
|
||||
start_page,
|
||||
)
|
||||
if break_at is None:
|
||||
continue
|
||||
if break_at > int(table.getRows().getCount()):
|
||||
if break_at > row_count:
|
||||
continue
|
||||
|
||||
had_header = _table_has_header_row(table)
|
||||
@@ -1169,9 +1225,9 @@ def _fix_pass(uno, ctx, doc, tables, listings, repeat_header, details):
|
||||
details.append(
|
||||
"split: {0} {1} @row {2}".format(caption.kind, caption.number, break_at)
|
||||
)
|
||||
return made
|
||||
return made, cut_page
|
||||
|
||||
return made
|
||||
return made, cut_page
|
||||
|
||||
|
||||
def run_worker(port, path, engine, tables, listings, repeat_header):
|
||||
@@ -1187,14 +1243,30 @@ def run_worker(port, path, engine, tables, listings, repeat_header):
|
||||
doc, uno, ctx, tables, listings, details
|
||||
)
|
||||
_repair_split_table_borders(doc, tables, listings, details)
|
||||
for _ in range(MAX_PASSES):
|
||||
targets = _count_split_targets(doc, tables, listings)
|
||||
passes_done = 0
|
||||
start_page = 1
|
||||
while passes_done < continuation_pass_limit(targets, splits):
|
||||
if passes_done >= PASS_SAFETY_CAP:
|
||||
details.append("skip: pass safety cap")
|
||||
break
|
||||
_ensure_pagination(uno, ctx, doc)
|
||||
made = _fix_pass(
|
||||
uno, ctx, doc, tables, listings, repeat_header, details
|
||||
made, cut_page = _fix_pass(
|
||||
uno, ctx, doc, tables, listings, repeat_header, details, start_page
|
||||
)
|
||||
passes_done += 1
|
||||
if made == 0:
|
||||
if start_page > 1:
|
||||
start_page = 1
|
||||
details.append("recheck: from page 1")
|
||||
continue
|
||||
break
|
||||
splits += made
|
||||
if cut_page:
|
||||
start_page = resume_page_before_cut(cut_page)
|
||||
details.append(
|
||||
"resume: page {0} after cut at {1}".format(start_page, cut_page)
|
||||
)
|
||||
doc = _reload_document(uno, ctx, doc, path, engine)
|
||||
_ensure_pagination(uno, ctx, doc)
|
||||
repaired += _repair_missing_continuations(
|
||||
|
||||
Reference in New Issue
Block a user