mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-10 21:11:52 +00:00
fix(print): apply cached papers immediately, refresh in background, and document functions
This commit is contained in:
1 parent
25b6280ac6
commit
f1e2c49d55
5 files changed
+69
-9
No files matched your search
@@ -191,6 +191,7 @@ fn spooled(job: &Job) -> Job {
|
||||
}
|
||||
}
|
||||
|
||||
/// Submit a PDF to the system print spooler for the configured `job`.
|
||||
pub fn submit(pdf: &[u8], job: &Job) -> Result<String, crate::PrintError> {
|
||||
craft_print::submit(pdf, &spooled(job)).map_err(|e| crate::PrintError::Spool(e.to_string()))
|
||||
}
|
||||
@@ -201,6 +202,7 @@ pub fn submit_with_progress(pdf: &[u8], job: &Job, progress: &mut dyn FnMut(usiz
|
||||
craft_print::submit_with_progress(pdf, &spooled(job), progress).map_err(|e| crate::PrintError::Spool(e.to_string()))
|
||||
}
|
||||
|
||||
/// Opens the printer driver's native Printing Preferences window (Windows `printui.dll`).
|
||||
pub fn open_printer_preferences(printer: &str) -> Result<(), crate::PrintError> {
|
||||
craft_print::open_printer_preferences(printer).map_err(|e| crate::PrintError::Spool(e.to_string()))
|
||||
}
|
||||
@@ -235,11 +237,13 @@ pub fn printer_papers(printer: &str) -> Vec<Paper> {
|
||||
papers
|
||||
}
|
||||
|
||||
/// The paper sizes supported by `printer` (fallback for non-Windows platforms).
|
||||
#[cfg(not(windows))]
|
||||
pub fn printer_papers(_printer: &str) -> Vec<Paper> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
/// Match `paper_pts` against detected driver `papers` within a 1.0 pt tolerance.
|
||||
#[cfg(windows)]
|
||||
fn resolve_paper_name(papers: &[Paper], paper_pts: (f64, f64)) -> Paper {
|
||||
let w_pts = (paper_pts.0 * 100.0).round() / 100.0;
|
||||
|
||||
@@ -36,6 +36,7 @@ fn rgb_triple(v: &serde_json::Value) -> Option<[f64; 3]> {
|
||||
}
|
||||
|
||||
impl PdfCraftApp {
|
||||
/// Sets the user's interface theme preference (Light, Dark, or System).
|
||||
pub fn set_theme_preference(&mut self, preference: ThemePreference) {
|
||||
self.theme_preference = preference;
|
||||
if let Some(ctx) = self.ctx.clone() {
|
||||
|
||||
@@ -151,6 +151,7 @@ impl Drop for WakeOnExit {
|
||||
}
|
||||
|
||||
impl PdfCraftApp {
|
||||
/// Open the Print dialog, preselecting the default printer and reading papers in the background.
|
||||
pub fn open_print(&mut self) {
|
||||
let Some((i, _)) = self.active_ids() else { return };
|
||||
let (printers, printers_loading) = match self.printer_source.clone() {
|
||||
@@ -241,6 +242,7 @@ impl PdfCraftApp {
|
||||
self.print_draft.crop_pages = Some(pages);
|
||||
}
|
||||
|
||||
/// Read the printer list in the background off the GUI thread; `poll_print` picks it up.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn list_printers_in_background(&mut self, source: PrinterSource) {
|
||||
// A list already being read is as fresh as a new one would be.
|
||||
@@ -302,8 +304,13 @@ impl PdfCraftApp {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn read_papers_in_background(&mut self, printer: String) {
|
||||
if let Some((papers, default_paper)) = self.print_tasks.papers_cache.get(&printer).cloned() {
|
||||
self.receive_papers(printer, papers, default_paper);
|
||||
return;
|
||||
let d = &mut self.print_draft;
|
||||
if d.printer.as_deref() == Some(printer.as_str()) {
|
||||
d.apply_printer_papers(papers);
|
||||
if !d.paper_overridden {
|
||||
d.apply_default_paper(default_paper);
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.print_tasks.papers.iter().any(|(p, _)| *p == printer) {
|
||||
return;
|
||||
@@ -347,14 +354,18 @@ impl PdfCraftApp {
|
||||
/// The papers and default paper read for `printer` arrived, or the read died.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn receive_papers(&mut self, printer: String, papers: Vec<spool::Paper>, default_paper: Option<spool::Paper>) {
|
||||
self.print_tasks.papers_cache.insert(printer.clone(), (papers.clone(), default_paper.clone()));
|
||||
if !papers.is_empty() || default_paper.is_some() {
|
||||
self.print_tasks.papers_cache.insert(printer.clone(), (papers.clone(), default_paper.clone()));
|
||||
}
|
||||
let d = &mut self.print_draft;
|
||||
if d.papers_loading.as_deref() == Some(printer.as_str()) {
|
||||
d.papers_loading = None;
|
||||
}
|
||||
if d.printer.as_deref() == Some(printer.as_str()) {
|
||||
d.apply_printer_papers(papers);
|
||||
if !d.paper_overridden {
|
||||
if !papers.is_empty() {
|
||||
d.apply_printer_papers(papers);
|
||||
}
|
||||
if !d.paper_overridden && default_paper.is_some() {
|
||||
d.apply_default_paper(default_paper);
|
||||
}
|
||||
}
|
||||
@@ -414,13 +425,14 @@ impl PdfCraftApp {
|
||||
self.print_tasks.printers = None;
|
||||
let d = &mut self.print_draft;
|
||||
// A picked printer that is no longer listed falls back to the default too.
|
||||
let changed = if !d.printer_picked || !offered(d.printer.as_deref(), &printers) {
|
||||
let new_printer = if !d.printer_picked || !offered(d.printer.as_deref(), &printers) {
|
||||
d.printer_picked = false;
|
||||
d.printer = default_printer(&printers);
|
||||
true
|
||||
default_printer(&printers)
|
||||
} else {
|
||||
false
|
||||
d.printer.clone()
|
||||
};
|
||||
let changed = d.printer != new_printer;
|
||||
d.printer = new_printer;
|
||||
d.printers = printers;
|
||||
d.printers_loading = false;
|
||||
if changed && let Some(p) = d.printer.clone() {
|
||||
@@ -486,6 +498,7 @@ impl PdfCraftApp {
|
||||
}
|
||||
}
|
||||
|
||||
/// Report the outcome of a finished print job to the user.
|
||||
fn report_print_job(&mut self, printer: &str, result: Result<String, String>) {
|
||||
match result {
|
||||
Ok(msg) if msg.is_empty() => self.notify(crate::i18n::fmt(tl!("Sent to {printer}"), &[("printer", printer)])),
|
||||
|
||||
@@ -361,6 +361,7 @@ impl PrintDraft {
|
||||
})
|
||||
}
|
||||
|
||||
/// Whether multiple pages per sheet should be cut and stacked into sorted piles.
|
||||
fn cut_and_stack(&self) -> bool {
|
||||
self.handling == Handling::Multiple && self.order == PageOrder::CutStack
|
||||
}
|
||||
|
||||
@@ -941,6 +941,47 @@ fn auto_select_default_paper_preserves_user_orientation() {
|
||||
assert_eq!(draft.orientation, pdfcraft_engine::print::Orientation::Landscape);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cached_papers_apply_immediately_and_refresh_in_background() {
|
||||
use pdfcraft_engine::print::spool;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
let calls = Arc::new(AtomicUsize::new(0));
|
||||
let calls_clone = calls.clone();
|
||||
|
||||
let mut h = harness();
|
||||
h.state_mut().printer_source =
|
||||
Some(Arc::new(|| vec![spool::Printer { name: "Cached Printer".into(), default: true, two_sided: None, description: String::new() }]));
|
||||
h.state_mut().printer_papers_source = Some(Arc::new(move |_| {
|
||||
calls_clone.fetch_add(1, Ordering::SeqCst);
|
||||
vec![("A4".into(), (595.28, 841.89))]
|
||||
}));
|
||||
h.state_mut().default_paper_source =
|
||||
Some(Arc::new(|printer: &str| if printer == "Cached Printer" { Some(("A4".into(), (595.28, 841.89))) } else { None }));
|
||||
|
||||
assert!(h.state_mut().execute("print.dialog"));
|
||||
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(10);
|
||||
while (h.state().print_draft.printers_loading || h.state().print_draft.papers_loading.is_some()) && std::time::Instant::now() < deadline {
|
||||
h.run_steps(1);
|
||||
std::thread::sleep(std::time::Duration::from_millis(5));
|
||||
}
|
||||
assert_eq!(calls.load(Ordering::SeqCst), 1);
|
||||
let a4 = h.state().print_draft.paper;
|
||||
|
||||
h.state_mut().dialog = None;
|
||||
|
||||
assert!(h.state_mut().execute("print.dialog"));
|
||||
assert_eq!(h.state().print_draft.paper, a4);
|
||||
|
||||
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(10);
|
||||
while h.state().print_draft.papers_loading.is_some() && std::time::Instant::now() < deadline {
|
||||
h.run_steps(1);
|
||||
std::thread::sleep(std::time::Duration::from_millis(5));
|
||||
}
|
||||
assert_eq!(calls.load(Ordering::SeqCst), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn restored_paper_keeps_preview_and_saved_sheet_dimensions() {
|
||||
use pdfcraft_engine::print::{self, PAPERS};
|
||||
|
||||
Reference in new issue
Block a user