Skip to content

refactor(convert): move 6 PDF-export converters off the UI thread#36

Merged
nelsonduarte merged 1 commit into
mainfrom
refactor/convert-pdf-export-background
May 6, 2026
Merged

refactor(convert): move 6 PDF-export converters off the UI thread#36
nelsonduarte merged 1 commit into
mainfrom
refactor/convert-pdf-export-background

Conversation

@nelsonduarte
Copy link
Copy Markdown
Owner

Summary

Migrate the remaining 6 PDF-export converters (_convert_docx / _convert_txt / _convert_pptx / _convert_xlsx / _convert_html / _convert_epub) from synchronous UI-thread loops with QApplication.processEvents() to BasePage._run_background, following the same pattern compress / OCR / convert-images / watermark / N-up already use.

Why

PPTX and DOCX in particular render each page at high DPI (PPTX uses 2× pixmap matrix and embeds the image per slide); on multi-page documents the UI freezes for tens of seconds and the Cancel button is effectively dead because processEvents only runs between iterations. After this change the dialog is responsive and worker.is_cancelled() is honoured at every page boundary.

Changes

  • app/tools/convert.py — 6 methods migrated. Each follows the canonical shape:
    • Pre-flight on main thread: optional-dep ImportError → localized QMessageBox, open doc once for page_count, capture self._pdf_password.
    • do_work re-opens fitz, authenticates if needed, runs the per-page loop emitting worker.progress.emit(i, "i+1/total…") and checking worker.is_cancelled().
    • on_done on main thread shows the success message.
  • app/translations.json — 3 previously-missing dep keys × 8 languages (tool.convert.dep_pptx / dep_xlsx / dep_epub). Before this PR those three converters fell through to the generic str(e) error on missing optional deps.

Test plan

  • Smoke test on Ubuntu 26.04 + Py3.14.4 (offscreen): drives all 6 converters on a 4-page sample, asserts on_done fires on the main thread and the output file is produced. All 6 pass (txt 174B / docx 36KB / pptx 60KB / xlsx 6KB / html 563B / epub 3KB).
  • Live GUI on Windows + Py3.14: large-document export no longer freezes the UI; Cancel button aborts mid-document.
  • Spot-check encrypted-source path (password prompted in viewer, export run in compact mode).
  • Verify error path: rename a dep wheel temporarily and confirm the localized "library required" dialog appears.

Remaining work

After this lands, the only tools still doing heavy work synchronously are import_pdf.py (8 conversion paths, each needs per-converter migration because they shell into different third-party libs) and page_numbers.py (has a mid-flow QMessageBox.question about replacing existing numbers, needs main-thread split before/after the prompt). Tracked in [feedback_background_tasks.md](memory note).

🤖 Generated with Claude Code

The PDF→DOCX / TXT / PPTX / XLSX / HTML / EPUB conversions still ran
synchronously on the main thread, polling QApplication.processEvents()
between pages. UI froze and the cancel button was effectively useless
on multi-page documents (PPTX in particular renders each page at 2x
DPI, several seconds per page).

Migrate all 6 to BasePage._run_background, mirroring the pattern from
the already-migrated _convert_images:
- Pre-flight on the main thread: dependency check (ImportError →
  proper localized message via QMessageBox), open the doc once for
  page-count, capture self._pdf_password into a local before the
  closure.
- do_work re-opens the fitz doc, re-authenticates if needed, runs
  the per-page extraction loop, emits worker.progress.emit(i, label)
  per page, and checks worker.is_cancelled() at each iteration so
  the Cancel button on the progress dialog actually aborts.
- on_done runs on the main thread via the @slot dispatcher and
  shows the success toast / message box.

Add 3 new i18n keys × 8 languages for the previously-missing
dependency-error messages (tool.convert.dep_pptx / dep_xlsx /
dep_epub) — before this PR those formats fell through to the generic
str(e) error.

Verified end-to-end on Ubuntu 26.04 + Py3.14.4 with a smoke test
that runs all 6 converters on a 4-page sample and asserts on_done
fires on the main thread + the output file is produced.

Remaining background-task TODOs: import_pdf.py (8 paths) and
page_numbers.py (mid-flow QMessageBox prompt).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nelsonduarte nelsonduarte merged commit 8e64bb7 into main May 6, 2026
3 checks passed
@nelsonduarte nelsonduarte deleted the refactor/convert-pdf-export-background branch May 6, 2026 12:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant