diff --git a/crates/ui-egui/src/editing/save.rs b/crates/ui-egui/src/editing/save.rs index 446aba1fc5..a2830d680d 100644 --- a/crates/ui-egui/src/editing/save.rs +++ b/crates/ui-egui/src/editing/save.rs @@ -171,17 +171,11 @@ impl PdfCraftApp { /// The Lock signatures dialog answered (#2149): lock the document's Fill & Sign marks into /// its pages first when `lock`, then save as was asked. With `remember`, the answer becomes - /// the preference (flatten on every save, or never ask again). + /// the preference (flatten on every save, or never ask again). Nothing changes when locking + /// fails: the document still counts as holding a placed signature, so the next save asks + /// again, and the answer isn't remembered. pub(crate) fn answer_lock_signatures(&mut self, lock: bool, remember: bool) { let Some(p) = self.pending_lock.take() else { return }; - self.placed_signatures.remove(&p.id); - if remember { - if lock { - self.flatten_fill_sign_on_save = true; - } else { - self.ask_to_lock_signatures = false; - } - } if lock && !self.flatten_fill_sign_on_save { let before = self.session.get(p.id).map(|d| d.edit_generation()); if let Err(e) = self.session.apply(p.id, pdfcraft_engine::Edit::FlattenFillSign) { @@ -195,6 +189,14 @@ impl PdfCraftApp { view.document_changed(&doc.info); } } + self.placed_signatures.remove(&p.id); + if remember { + if lock { + self.flatten_fill_sign_on_save = true; + } else { + self.ask_to_lock_signatures = false; + } + } if let Some(index) = self.views.iter().position(|v| v.id == p.id) { self.save_then(index, p.target, p.after); } diff --git a/crates/ui-egui/tests/it/fill_sign.rs b/crates/ui-egui/tests/it/fill_sign.rs index 1bd6f53ff9..54af2288f0 100644 --- a/crates/ui-egui/tests/it/fill_sign.rs +++ b/crates/ui-egui/tests/it/fill_sign.rs @@ -1802,6 +1802,47 @@ fn the_first_save_after_placing_a_signature_asks_to_lock_it() { let _ = std::fs::remove_file(&out); } +/// #2348 review: when locking the signature fails (here the document's security allows comments +/// but not changes), nothing is lost: the next save asks again, and "Don't ask again" isn't +/// remembered. +#[test] +fn a_lock_that_fails_keeps_the_question() { + let out = std::env::temp_dir().join(format!("pdfcraft-lock-fails-{}.pdf", std::process::id())); + let mut doc = pdfcraft_cos::Document::open(std::sync::Arc::new(FIXTURE.to_vec())).unwrap(); + doc.set_encryption(&pdfcraft_cos::NewEncryption { + algorithm: pdfcraft_cos::Algorithm::Aes256, + user_password: "", + owner_password: "owner", + // Everything but bit 4, modifying the document. + permissions: -1 ^ 8, + encrypt_metadata: true, + seed: [4; 32], + }) + .unwrap(); + let mut h = harness_bytes(&pdfcraft_cos::write_full(&doc, &Default::default()).unwrap()); + h.state_mut().save_override = Some(out.to_string_lossy().into_owned()); + h.state_mut().signature = Some(SavedSig::Typed("Ada Lovelace".into())); + h.state_mut().execute("sign.fill.signature"); + h.run_steps(2); + click(&mut h, 40.0, 300.0); + let signed = |h: &Harness<'static, PdfCraftApp>| { + h.state().session.get(h.state().views[0].id).unwrap().info.annotations.iter().filter(|a| a.fill_sign).count() + }; + assert_eq!(signed(&h), 1, "comments are allowed"); + assert!(!h.state_mut().save_active(SaveTarget::InPlace), "asks first"); + h.run_steps(2); + h.get_by_label("Don't ask again").click(); + h.run_steps(1); + h.get_by_label("Lock and save").click(); + h.run_steps(3); + assert_eq!(signed(&h), 1, "changes aren't allowed: still a comment"); + assert!(!h.state().flatten_fill_sign_on_save, "the failed answer isn't remembered"); + assert!(!h.state_mut().save_active(SaveTarget::InPlace), "the next save asks again"); + h.run_steps(2); + h.get_by_label("Lock your signature into the page?"); + let _ = std::fs::remove_file(&out); +} + /// #2149: Cancel saves nothing, and Keep editable with Don't ask again turns the question off. #[test] fn cancelling_the_lock_question_saves_nothing() {