tools/lab/wonderink-workspace-check launches the installed command again and again against a stand-in for WonderInk's start page whose sign-in is Basic auth, as WonderInk's is: restored after 5 and 90 minutes; fresh after two hours and a minute, a day and a week; reopened untouched until it lapses; a click after a restore counts and the restore does not; a busy page and an untouched print preview do not; Print does; closed, reordered, worksheet and missing-worksheet tabs; killed outright; a restore that crashes twice; corrupt, future-format and half-written files; the file holding no credential; restored tabs printing. 59 checks. The print check follows every kind of link on a signed-in page with one click — new tab in front for links and window.open, nothing for buttons and anchors, same-tab for no target, Back, closing — and prints a PDF and a picture reached by a link, and a page after several tabs. 0.2.6.3's scenarios are unchanged. Co-Authored-By: Claude Opus 5.5 <[email protected]>
447 lines
26 KiB
Python
447 lines
26 KiB
Python
"""Drive Wonder Ink's print preview through one scenario, headless.
|
|
|
|
usage: wonderink-print-rig.py WONDERINK_COMMAND SCENARIO
|
|
|
|
Run by tools/lab/wonderink-print-check inside the lab, against the
|
|
command the package installed. It presses the preview's own buttons the
|
|
way a teacher would, and prints what happened; the check around it asks
|
|
CUPS what actually arrived.
|
|
"""
|
|
import importlib.machinery, importlib.util, sys, time, faulthandler, gc, os
|
|
faulthandler.enable()
|
|
path, scenario = sys.argv[1], sys.argv[2]
|
|
loader = importlib.machinery.SourceFileLoader("wonderink", path)
|
|
spec = importlib.util.spec_from_loader("wonderink", loader)
|
|
wi = importlib.util.module_from_spec(spec); loader.exec_module(wi)
|
|
|
|
from pathlib import Path
|
|
from PyQt6.QtCore import QTimer, QUrl
|
|
from PyQt6.QtGui import QPdfWriter, QPainter, QFont, QPageSize
|
|
from PyQt6.QtWidgets import QApplication
|
|
from PyQt6.QtWebEngineCore import QWebEngineProfile, QWebEngineSettings
|
|
|
|
notes = []
|
|
wi.notify = lambda s, b: (notes.append(s), print("NOTIFY", s, "|", b, flush=True))
|
|
app = QApplication(sys.argv)
|
|
# Wonder Ink's own profile, settings and all — not one of the rig's.
|
|
profile = wi.build_profile(app, "rig")
|
|
window = wi.WonderInk(profile)
|
|
profile.downloadRequested.connect(window.on_download)
|
|
window.resize(1280, 800); window.show()
|
|
t0 = time.monotonic()
|
|
def stamp(m): print(f"[{time.monotonic()-t0:6.2f}s] {m}", flush=True)
|
|
|
|
def lesson(view, title="Noahs Ark lesson"):
|
|
view.setHtml(f"<html><head><title>{title}</title></head><body>" + "".join(
|
|
f"<h1>{title}, part {i}</h1><p>{'Noah built an ark. ' * 80}</p>" for i in range(5)
|
|
) + "</body></html>", QUrl("https://app.wonderink.org/lesson"))
|
|
|
|
def worksheet(name="Colour the Ark"):
|
|
d = wi.DOWNLOADS; d.mkdir(parents=True, exist_ok=True)
|
|
p = d / f"{name}.pdf"
|
|
w = QPdfWriter(str(p)); w.setPageSize(QPageSize(QPageSize.PageSizeId.Letter)); w.setResolution(300)
|
|
pa = QPainter(w); pa.setFont(QFont("DejaVu Sans", 28))
|
|
pa.drawText(200, 400, f"WORKSHEET {name} page one"); pa.drawRect(200, 600, 2000, 1500)
|
|
w.newPage(); pa.drawText(200, 400, f"WORKSHEET {name} page two"); pa.end()
|
|
return p
|
|
|
|
def when(cond, then, label, limit=30):
|
|
start = time.monotonic()
|
|
def poll():
|
|
try: ok = cond()
|
|
except Exception as e: ok = False
|
|
if ok: return then()
|
|
if time.monotonic() - start > limit:
|
|
stamp(f"GAVE UP waiting for {label}"); app.exit(4); return
|
|
QTimer.singleShot(100, poll)
|
|
QTimer.singleShot(100, poll)
|
|
|
|
def preview(): return window._preview
|
|
def ready(): return preview() is not None and preview()._pdf is not None
|
|
def describe(d):
|
|
return f"picture={d._picture_box.isVisible()} shown={(d._pdf, d._page) in d._images} pages={d._pages} printers={[d._printer.itemText(i) for i in range(d._printer.count())]} paper={d.paper()} colour_offered={d._colour.isVisible()} status={d._status.text()!r}"
|
|
|
|
def shown_gray():
|
|
"""Is the page the preview is drawing grey, pixel for pixel?"""
|
|
pixmap = preview()._view._pixmap
|
|
return None if pixmap is None else pixmap.toImage().allGray()
|
|
|
|
def keep_preview():
|
|
import shutil
|
|
out = Path("/tmp/rig-out"); out.mkdir(exist_ok=True)
|
|
shutil.copy(preview()._pdf, out / "preview.pdf")
|
|
|
|
def toggles(sequence, then):
|
|
"""Color (0) and Black and white (1) in turn, as a teacher would, each shown before the next."""
|
|
def step(i):
|
|
if i == len(sequence): return then()
|
|
start = time.monotonic(); preview()._colour.setCurrentIndex(sequence[i])
|
|
def shown():
|
|
d = preview()
|
|
stamp(f"TOGGLE {i} want={'gray' if sequence[i] else 'colour'} took={time.monotonic() - start:.2f} "
|
|
f"pdf={d._pdf.name} source={d._source.name} page={d._page}/{d._pages} shown_gray={shown_gray()}")
|
|
step(i + 1)
|
|
when(ready, shown, f"toggle {i}")
|
|
step(0)
|
|
|
|
def colour_lesson(view, title="Rainbow lesson"):
|
|
# Backgrounds do not print, so the colour is in the words and the drawings.
|
|
shapes = ("<svg width='600' height='120'><circle cx='60' cy='60' r='50' fill='#e00000'/>"
|
|
"<rect x='130' y='10' width='200' height='100' fill='#0050e0'/>"
|
|
"<circle cx='450' cy='60' r='50' fill='#00a000'/></svg>")
|
|
view.setHtml(f"<html><head><title>{title}</title></head><body>" + "".join(
|
|
f"<h1 style='color:#c00'>{title}, part {i}</h1>{shapes}"
|
|
f"<p style='color:#060'>{'God put a rainbow in the sky. ' * 60}</p>" for i in range(4)
|
|
) + "</body></html>", QUrl("https://app.wonderink.org/rainbow"))
|
|
|
|
def colour_worksheet(name="Colour the Rainbow"):
|
|
from PyQt6.QtGui import QColor
|
|
d = wi.DOWNLOADS; d.mkdir(parents=True, exist_ok=True)
|
|
p = d / f"{name}.pdf"
|
|
w = QPdfWriter(str(p)); w.setPageSize(QPageSize(QPageSize.PageSizeId.Letter)); w.setResolution(300)
|
|
pa = QPainter(w); pa.setFont(QFont("DejaVu Sans", 28))
|
|
for page, colours in enumerate((("#e00000", "#ff9900"), ("#00a000", "#0050e0"))):
|
|
if page: w.newPage()
|
|
pa.setPen(QColor(colours[0])); pa.drawText(200, 400, f"WORKSHEET {name} page {page + 1}")
|
|
pa.fillRect(200, 600, 1000, 800, QColor(colours[1]))
|
|
pa.end()
|
|
return p
|
|
|
|
def finish(code=0):
|
|
stamp(f"RESULT notes={notes} preview_open={preview() is not None} tabs={window._tabs.count()}")
|
|
QTimer.singleShot(1500, lambda: app.exit(code))
|
|
|
|
def press_print(then=None):
|
|
d = preview(); stamp("PREVIEW " + describe(d))
|
|
d._print.click()
|
|
stamp(f"after Print: open={preview() is not None} status={d._status.text() if preview() else ''!r}")
|
|
(then or finish)()
|
|
|
|
actions = {
|
|
"web": lambda view: when(ready, press_print, "preview"),
|
|
"cancel": lambda view: when(ready, lambda: (stamp("PREVIEW " + describe(preview())), preview()._cancel.click(), finish()), "preview"),
|
|
"options": lambda view: when(ready, lambda: (
|
|
preview()._which.setCurrentIndex(1), preview()._range.setText("2-3"),
|
|
preview()._copies.setValue(2), preview()._colour.setCurrentIndex(1),
|
|
when(ready, press_print, "black and white")), "preview"),
|
|
"bad-range": lambda view: when(ready, lambda: (
|
|
preview()._which.setCurrentIndex(1), preview()._range.setText("7"), preview()._print.click(),
|
|
stamp(f"bad range: open={preview() is not None} status={preview()._status.text()!r}"),
|
|
preview()._range.setText("1"), press_print()), "preview"),
|
|
"broken": lambda view: when(ready, lambda: (
|
|
preview()._printer.setCurrentText("Refusing"),
|
|
stamp(f"switched to Refusing: paper={preview().paper()} status={preview()._status.text()!r}"),
|
|
when(ready, lambda: (
|
|
stamp(f"re-rendered on {preview().paper()}: pages={preview()._pages}"),
|
|
preview()._print.click(),
|
|
stamp(f"broken: open={preview() is not None} status={preview()._status.text()!r}"),
|
|
preview()._cancel.click(), finish()), "re-render")), "preview"),
|
|
"page-closes-itself": lambda view: when(ready, lambda: (
|
|
view.page().runJavaScript("window.close()"),
|
|
when(lambda: preview() and "closed" in preview()._status.text(), lambda: (
|
|
stamp(f"after page closed: status={preview()._status.text()!r} print_enabled={preview()._print.isEnabled()}"),
|
|
preview()._cancel.click(), finish()), "closed message")), "preview"),
|
|
"close-window": lambda view: when(ready, lambda: (stamp("closing window with preview open"), window.close()), "preview"),
|
|
"page-prints-again": lambda view: when(ready, lambda: (
|
|
view.page().runJavaScript("window.print()"),
|
|
QTimer.singleShot(800, lambda: (stamp(f"second request while open: still one preview={preview() is not None}"), press_print()))), "preview"),
|
|
}
|
|
|
|
SITE = "http://127.0.0.1:8094"
|
|
|
|
if scenario.startswith("bw-"):
|
|
# bw-web: a colourful lesson, turned to page 2, Color and Black and white
|
|
# back and forth, then page 2 twice in black and white.
|
|
# bw-pdf: a colourful worksheet, all of it, in black and white.
|
|
# bw-colour-again: black and white, then back to Color, then Print.
|
|
# bw-cancel: black and white, then Cancel.
|
|
if scenario == "bw-pdf":
|
|
window.open_pdf(colour_worksheet()); view = window.current()
|
|
else:
|
|
view = window.open_tab(); colour_lesson(view)
|
|
def colour_first():
|
|
stamp(f"COLOUR FIRST shown_gray={shown_gray()} pdf={preview()._pdf.name}")
|
|
if scenario == "bw-web":
|
|
preview()._turn(1)
|
|
toggles([1, 0, 1, 0, 1], lambda: (
|
|
preview()._which.setCurrentIndex(1), preview()._range.setText("2"),
|
|
preview()._copies.setValue(2), keep_preview(), press_print()))
|
|
elif scenario == "bw-pdf":
|
|
toggles([1], lambda: (keep_preview(), press_print()))
|
|
elif scenario == "bw-colour-again":
|
|
toggles([1, 0], lambda: (keep_preview(), press_print()))
|
|
else:
|
|
toggles([1], lambda: (stamp("PREVIEW " + describe(preview())), preview()._cancel.click(), finish()))
|
|
begin = lambda *_: (QTimer.singleShot(0, lambda: window.print_view(view)), when(ready, colour_first, "preview"))
|
|
if scenario == "bw-pdf":
|
|
QTimer.singleShot(2500, begin)
|
|
else:
|
|
view.loadFinished.connect(begin)
|
|
elif scenario.startswith("links:"):
|
|
# links:follow every kind of link on the lab's signed-in links page,
|
|
# clicked in turn: what opens where, and what does not
|
|
# links:pdf a worksheet reached by a link, printed
|
|
# links:image a picture reached by a link, printed as a picture
|
|
# links:image-rclick the same picture, right-click Print image
|
|
# links:tabs-print several links opened, some closed, then the page printed
|
|
from PyQt6.QtCore import QEvent, QPointF, Qt
|
|
from PyQt6.QtGui import QMouseEvent
|
|
from PyQt6.QtWidgets import QApplication as Application
|
|
variant = scenario.split(":", 1)[1]
|
|
links_view = window.open_tab(); links_view.load(QUrl(f"{SITE}/login"))
|
|
def on_links():
|
|
return links_view.url().path() == "/lesson" or links_view.url().path() == "/links"
|
|
def click_in(view, selector, then, button=Qt.MouseButton.LeftButton):
|
|
js = ("(function(){var e=document.querySelector(%r); if(!e) return null; e.scrollIntoView({block:'center'});"
|
|
"var r=e.getBoundingClientRect(); return [r.x+r.width/2, r.y+r.height/2]})()" % selector)
|
|
def at(xy):
|
|
if not xy:
|
|
stamp(f"NO {selector}"); return finish(6)
|
|
zoom = view.zoomFactor(); point = QPointF(xy[0] * zoom, xy[1] * zoom)
|
|
for kind, buttons in ((QEvent.Type.MouseButtonPress, button), (QEvent.Type.MouseButtonRelease, Qt.MouseButton.NoButton)):
|
|
Application.sendEvent(view.focusProxy(), QMouseEvent(kind, point, QPointF(view.mapToGlobal(point)),
|
|
button, buttons, Qt.KeyboardModifier.NoModifier))
|
|
QTimer.singleShot(1500, then)
|
|
view.page().runJavaScript(js, at)
|
|
def tabs():
|
|
return [window._tabs.widget(i).url().toString().replace(SITE, "") for i in range(window._tabs.count())]
|
|
def report(label):
|
|
current = window.current()
|
|
stamp(f"LINK {label} tabs={len(tabs())} current={current.url().toString().replace(SITE, '')!r} "
|
|
f"current_is_new={current is not links_view} worksheet={current in window._pdf_views}")
|
|
def back_to_links():
|
|
window._tabs.setCurrentWidget(links_view)
|
|
def go_links(then):
|
|
# From the lesson the site sent us to after signing in, to the links page, in this tab.
|
|
links_view.load(QUrl(f"{SITE}/links"))
|
|
when(lambda: links_view.url().path() == "/links", lambda: QTimer.singleShot(1200, then), "the links page")
|
|
steps = []
|
|
if variant == "follow":
|
|
order = [("#blank", "text link, target=_blank, to a picture"), ("#external", "another site"),
|
|
("#linked-picture", "a linked picture"), ("#pdf", "a worksheet PDF"),
|
|
("#popup", "a lesson button that opens a window"), ("#button", "a lesson button"),
|
|
("#anchor", "an in-page anchor"), ("#same", "a link with no target")]
|
|
def next_link(i=0):
|
|
if i == len(order):
|
|
# Back, as the right-click menu's Back does, then close every tab the links opened.
|
|
links_view.page().triggerAction(links_view.page().WebAction.Back)
|
|
def closed_all():
|
|
report("after Back")
|
|
for view in [window._tabs.widget(j) for j in range(window._tabs.count())]:
|
|
if view is not links_view:
|
|
window.close_tab(window._tabs.indexOf(view))
|
|
QTimer.singleShot(800, lambda: (report("after closing the opened tabs"),
|
|
stamp(f"TABS {tabs()}"), finish()))
|
|
return QTimer.singleShot(2000, closed_all)
|
|
selector, label = order[i]
|
|
back_to_links()
|
|
click_in(links_view, selector, lambda: (report(f"{selector} ({label})"),
|
|
stamp(f"BUTTON {links_view.page().title()!r}") if selector == "#button" else None,
|
|
QTimer.singleShot(1500 if selector == "#pdf" else 200, lambda: next_link(i + 1))))
|
|
when(on_links, lambda: go_links(lambda: (report("start"), next_link())), "signed in")
|
|
elif variant in ("pdf", "image", "image-rclick", "tabs-print"):
|
|
target = {"pdf": "#pdf", "image": "#blank", "image-rclick": "#blank", "tabs-print": "#blank"}[variant]
|
|
def opened():
|
|
report(f"{target} opened")
|
|
view = window.current()
|
|
if variant == "pdf":
|
|
QTimer.singleShot(2500, lambda: (QTimer.singleShot(0, lambda: window.print_view(window.current())),
|
|
when(ready, lambda: (keep_preview(), press_print()), "worksheet preview")))
|
|
elif variant == "image":
|
|
QTimer.singleShot(0, lambda: window.print_view(view))
|
|
when(lambda: ready() and preview()._picture is not None, lambda: (
|
|
stamp(f"PICTURE picture_box={preview()._picture_box.isVisible()} image={preview()._picture.width()}x{preview()._picture.height()}"),
|
|
keep_preview(), press_print()), "picture preview")
|
|
elif variant == "image-rclick":
|
|
def menu_up(menu):
|
|
items = [a.text() for a in menu.actions() if a.text()]
|
|
stamp(f"MENU {items}")
|
|
action = next(a for a in menu.actions() if a.text() == "Print image…")
|
|
menu.close()
|
|
when(lambda: ready() and preview()._picture is not None, lambda: (
|
|
stamp(f"PICTURE picture_box={preview()._picture_box.isVisible()} image={preview()._picture.width()}x{preview()._picture.height()}"),
|
|
keep_preview(), press_print()), "picture preview")
|
|
QTimer.singleShot(0, action.trigger)
|
|
click_in(view, "img", lambda: when(lambda: Application.activePopupWidget() is not None,
|
|
lambda: menu_up(Application.activePopupWidget()), "menu"),
|
|
button=Qt.MouseButton.RightButton)
|
|
else:
|
|
# Three links opened, two of them closed again, then the page they came from printed.
|
|
def more():
|
|
back_to_links()
|
|
click_in(links_view, "#external", lambda: (back_to_links(), click_in(links_view, "#linked-picture", close_two)))
|
|
def close_two():
|
|
for view in [window._tabs.widget(j) for j in range(window._tabs.count())][-2:]:
|
|
window.close_tab(window._tabs.indexOf(view))
|
|
back_to_links(); report("before printing")
|
|
QTimer.singleShot(0, lambda: window.print_view(links_view))
|
|
when(ready, lambda: (keep_preview(), press_print()), "page preview")
|
|
more()
|
|
when(on_links, lambda: go_links(lambda: (back_to_links(), click_in(links_view, target, lambda: QTimer.singleShot(1500, opened)))), "signed in")
|
|
elif scenario.startswith("rclick"):
|
|
# A lesson behind a sign-in, with pictures in it; a real right-click.
|
|
# rclick-page on the words: the page prints
|
|
# rclick-image:ID:SIZE:POSITION[:gray] on a picture: that picture prints
|
|
# rclick-broken a picture that never loaded
|
|
# rclick-cancel a picture, then Cancel
|
|
from PyQt6.QtCore import QEvent, QPointF, Qt
|
|
from PyQt6.QtGui import QMouseEvent
|
|
from PyQt6.QtWidgets import QApplication as Application
|
|
parts = scenario.split(":")
|
|
target = {"rclick-page": "words", "rclick-page-gray": "words", "rclick-broken": "broken",
|
|
"rclick-cancel": "private-jpg"}.get(parts[0], parts[1] if len(parts) > 1 else "")
|
|
clipboard = Application.clipboard()
|
|
view = window.open_tab(); view.load(QUrl(f"{SITE}/login"))
|
|
page_ready = []
|
|
def poll_ready():
|
|
if view.url().path() == "/lesson":
|
|
view.page().runJavaScript("window.__ready === true", lambda ok: page_ready.append(1) if ok else None)
|
|
if not page_ready: QTimer.singleShot(200, poll_ready)
|
|
QTimer.singleShot(500, poll_ready)
|
|
def right_click(then):
|
|
js = ("(function(){var e=document.getElementById(%r);e.scrollIntoView({block:'center'});"
|
|
"var r=e.getBoundingClientRect();return [r.x+r.width/2,r.y+r.height/2]})()" % target)
|
|
def at(xy):
|
|
zoom = view.zoomFactor(); x, y = xy[0] * zoom, xy[1] * zoom
|
|
clipboard.setText("TEACHER'S TEXT, John 3:16")
|
|
stamp(f"RCLICK {target} at {x:.0f},{y:.0f} since={time.time():.3f}")
|
|
for kind, buttons in ((QEvent.Type.MouseButtonPress, Qt.MouseButton.RightButton),
|
|
(QEvent.Type.MouseButtonRelease, Qt.MouseButton.NoButton)):
|
|
Application.sendEvent(view.focusProxy(), QMouseEvent(
|
|
kind, QPointF(x, y), QPointF(view.mapToGlobal(QPointF(x, y))),
|
|
Qt.MouseButton.RightButton, buttons, Qt.KeyboardModifier.NoModifier))
|
|
when(lambda: Application.activePopupWidget() is not None,
|
|
lambda: then(Application.activePopupWidget()), "menu")
|
|
view.page().runJavaScript(js, at)
|
|
def choose(menu, text, after):
|
|
items = [a.text() for a in menu.actions() if a.text()]
|
|
stamp(f"MENU {items}")
|
|
action = next((a for a in menu.actions() if a.text() == text), None)
|
|
menu.close()
|
|
if action is None:
|
|
stamp(f"NO {text!r} IN THE MENU"); return finish(5)
|
|
after()
|
|
QTimer.singleShot(0, action.trigger)
|
|
def picture_ready():
|
|
d = preview(); return d is not None and d._picture is not None and d._pdf is not None
|
|
def clipboard_line():
|
|
stamp(f"CLIPBOARD {clipboard.text()!r}")
|
|
if parts[0] == "rclick-page":
|
|
go = lambda: right_click(lambda m: choose(m, "Print page…", lambda: when(ready, lambda: (
|
|
clipboard_line(), keep_preview(), press_print()), "page preview")))
|
|
elif parts[0] == "rclick-page-gray":
|
|
# The page with all its pictures, in black and white: the slow case.
|
|
def gray_page():
|
|
start = time.monotonic(); preview()._colour.setCurrentIndex(1)
|
|
when(ready, lambda: (
|
|
stamp(f"GRAY PAGE took={time.monotonic() - start:.1f} shown_gray={shown_gray()} pages={preview()._pages}"),
|
|
keep_preview(), press_print()), "black and white", limit=70)
|
|
go = lambda: right_click(lambda m: choose(m, "Print page…", lambda: when(ready, gray_page, "page preview")))
|
|
elif parts[0] == "rclick-broken":
|
|
go = lambda: right_click(lambda m: choose(m, "Print image…", lambda: when(
|
|
lambda: preview() is not None and "could not be taken" in preview()._status.text(), lambda: (
|
|
stamp(f"BROKEN status={preview()._status.text()!r} print_enabled={preview()._print.isEnabled()} "
|
|
f"pages={preview()._pages} picture={preview()._picture is not None}"),
|
|
clipboard_line(), preview()._cancel.click(), finish()), "the picture failing", limit=15)))
|
|
elif parts[0] == "rclick-cancel":
|
|
go = lambda: right_click(lambda m: choose(m, "Print image…", lambda: when(picture_ready, lambda: (
|
|
stamp("PREVIEW " + describe(preview())), clipboard_line(), preview()._cancel.click(), finish()),
|
|
"picture preview")))
|
|
else:
|
|
_, _, size, position, *colour = parts
|
|
def lay_out():
|
|
d = preview()
|
|
d._size.setCurrentIndex(d._size.findData(int(size)))
|
|
d._place.choose(position.replace("-", " "))
|
|
if colour == ["gray"]:
|
|
d._colour.setCurrentIndex(1)
|
|
QTimer.singleShot(900, lambda: when(ready, lambda: (
|
|
stamp(f"PICTURE picture_box={d._picture_box.isVisible()} image={d._picture.width()}x{d._picture.height()} "
|
|
f"title={d._title!r} shown_gray={shown_gray()}"),
|
|
clipboard_line(), keep_preview(), press_print()), "layout"))
|
|
go = lambda: right_click(lambda m: choose(m, "Print image…", lambda: when(picture_ready, lay_out, "picture preview")))
|
|
when(lambda: bool(page_ready), go, "the lesson and its pictures", limit=30)
|
|
elif scenario.startswith("picture:"):
|
|
# picture:FILE:SIZE:POSITION:PAPER:FILL[:color]
|
|
# Opens a picture on its own, chooses the layout with the preview's own
|
|
# controls, keeps the exact PDF the preview showed, then prints it.
|
|
_, name, size, position, paper, fill, *rest = scenario.split(":")
|
|
view = window.open_tab(); view.load(QUrl(f"http://127.0.0.1:8089/{name}"))
|
|
def ready_picture():
|
|
d = preview()
|
|
return d is not None and d._picture is not None and d._pdf is not None
|
|
def choose():
|
|
d = preview()
|
|
d._size.setCurrentIndex(d._size.findData(int(size)))
|
|
d._place.choose(position.replace("-", " "))
|
|
d._turned.setCurrentIndex(d._turned.findData(paper))
|
|
d._fill.setChecked(fill == "fill")
|
|
if rest and rest[0] == "gray":
|
|
d._colour.setCurrentIndex(1)
|
|
# The layout settles (120 ms), then black and white if asked for.
|
|
QTimer.singleShot(900, lambda: when(ready, keep_and_print, "layout"))
|
|
def keep_and_print():
|
|
import shutil
|
|
d = preview()
|
|
out = Path("/tmp/rig-out"); out.mkdir(exist_ok=True)
|
|
shutil.copy(d._pdf, out / "preview.pdf")
|
|
stamp(f"PICTURE picture_box={d._picture_box.isVisible()} size_enabled={d._size.isEnabled()} "
|
|
f"image={d._picture.width()}x{d._picture.height()} labels={d._colour_label.text()!r},{d._colour.itemText(0)!r} "
|
|
f"shown_gray={shown_gray()}")
|
|
press_print()
|
|
QTimer.singleShot(2500, lambda: (QTimer.singleShot(0, lambda: window.print_view(view)),
|
|
when(ready_picture, choose, "picture preview")))
|
|
elif scenario == "dark-page":
|
|
# A lesson page with a black background. Chrome does not print page
|
|
# backgrounds unless asked, and neither may Wonder Ink.
|
|
view = window.open_tab()
|
|
view.setHtml("<html><head><title>Night sky</title></head><body style='background:#000;color:#fff'>"
|
|
+ "<h1>Stars</h1>" + "<p>God made the stars. </p>" * 40 + "</body></html>",
|
|
QUrl("https://app.wonderink.org/night"))
|
|
def keep_dark():
|
|
import shutil
|
|
out = Path("/tmp/rig-out"); out.mkdir(exist_ok=True)
|
|
shutil.copy(preview()._pdf, out / "preview.pdf")
|
|
press_print()
|
|
view.loadFinished.connect(lambda ok: (QTimer.singleShot(0, lambda: window.print_view(view)),
|
|
when(ready, keep_dark, "dark preview")))
|
|
elif scenario == "repeat":
|
|
view = window.open_tab(); lesson(view); n = [0]
|
|
def once():
|
|
if n[0] == 5: return finish()
|
|
n[0] += 1; QTimer.singleShot(0, lambda: window.print_view(view))
|
|
when(ready, lambda: press_print(then=lambda: QTimer.singleShot(200, once)), "preview")
|
|
view.loadFinished.connect(lambda ok: once() if n[0] == 0 else None)
|
|
elif scenario in ("pdf", "pdf-options"):
|
|
window.open_pdf(worksheet()); view = window.current()
|
|
if scenario == "pdf-options":
|
|
actions["pdf-options"] = lambda view: when(ready, lambda: (
|
|
preview()._which.setCurrentIndex(1), preview()._range.setText("2"),
|
|
preview()._copies.setValue(3), preview()._colour.setCurrentIndex(1),
|
|
when(ready, press_print, "black and white")), "preview")
|
|
QTimer.singleShot(2500, lambda: (QTimer.singleShot(0, lambda: window.print_view(view)),
|
|
actions[scenario if scenario == "pdf-options" else "web"](view)))
|
|
elif scenario == "pdf-viewer-button":
|
|
# The viewer's own print button reaches the page as a print request.
|
|
window.open_pdf(worksheet()); view = window.current()
|
|
QTimer.singleShot(2500, lambda: (actions["web"](view), view.page().printRequested.emit()))
|
|
elif scenario == "inline":
|
|
view = window.open_tab(); view.load(QUrl("http://127.0.0.1:8089/ark.pdf"))
|
|
QTimer.singleShot(4000, lambda: (stamp(f"inline mime={window._mime.get(view)!r} shows_pdf={window._shows_pdf(view)}"),
|
|
QTimer.singleShot(0, lambda: window.print_view(view)),
|
|
when(ready, lambda: (stamp(f"worksheet tab opened: tabs={window._tabs.count()} current_is_pdf={window.current() in window._pdf_views}"), press_print()), "inline preview")))
|
|
else:
|
|
if scenario == "page-closes-itself":
|
|
lesson(window.open_tab(), "The other lesson")
|
|
view = window.open_tab(); lesson(view)
|
|
fired = []
|
|
def go(ok):
|
|
if fired: return
|
|
fired.append(1); QTimer.singleShot(0, lambda: window.print_view(view)); actions[scenario](view)
|
|
view.loadFinished.connect(go)
|
|
|
|
QTimer.singleShot(90000, lambda: (stamp("TIMEOUT"), app.exit(3)))
|
|
rc = app.exec()
|
|
stamp(f"EXIT {rc} scratch_left={sorted(p.name for p in Path(os.environ.get('XDG_RUNTIME_DIR','/tmp')).glob('wonderink-print-*'))}")
|
|
sys.exit(rc)
|