diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index a220644421..ac10aec000 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -642,6 +642,9 @@ pub struct DocView { pub fill_text: Option, /// A queued Fill & Sign signature: select it after its edit succeeds, then leave placement. pub(crate) fill_signature_page: Option, + /// The "Signature added … Lock now" notice was dismissed; placing another signature shows it + /// again (#2149). + pub(crate) lock_offer_dismissed: bool, pub(crate) signature_drag: crate::signature_drag::SignatureDrag, /// What the page modules claim for the cursor this frame; `document_area` sets it once. pub(crate) cursor: crate::page_cursor::PageCursor, @@ -736,6 +739,8 @@ pub enum ViewAction { CameraLevel, /// After Enhance page: leave the tool for this command (Crop pages, Organize pages). CameraNext(&'static str), + /// Lock now, on the notice shown after a signature is placed (#2149). + LockSignatures, } /// Default page right-click menu actions. @@ -1001,6 +1006,7 @@ impl DocView { marquee_done: None, fill_text: None, fill_signature_page: None, + lock_offer_dismissed: false, signature_drag: Default::default(), cursor: Default::default(), router: Default::default(), @@ -3030,6 +3036,12 @@ fn apply_notice(app: &mut PdfCraftApp, index: usize, notice: Option) { Some(Notice::Console) => app.dialog = Some(crate::Dialog::JsConsole), // Back on in Preferences ▸ General. Some(Notice::HideSecured) => app.show_secured_notice = false, + // Handled by the app with the other view actions (`ViewAction`). + Some(Notice::LockSignatures) => { + if let Some(view) = app.views.get_mut(index) { + view.pending_action = Some(ViewAction::LockSignatures); + } + } None => {} } } @@ -3499,13 +3511,19 @@ pub fn document_area(app: &mut PdfCraftApp, index: usize, ui: &mut egui::Ui) { (app.left_open && app.left == crate::LeftPanel::Tool("edit")) || matches!(app.quick_tool, QuickTool::AddText | QuickTool::EditText); let text_style = app.text_style.clone(); let show_secured_notice = app.show_secured_notice; + // Offer to lock a just-placed signature (#2149) on the same terms the save-time question + // asks: one is still there, saving doesn't lock it anyway, and the document isn't signed. + let lock_offer = !app.flatten_fill_sign_on_save + && app.placed_signatures.contains(&app.views[index].id) + && doc.info.annotations.iter().any(|a| a.fill_sign) + && !doc.is_signed(); let view = &mut app.views[index]; // Opened without the owner password and something is restricted. The notice says so unless // the user turned it off (#4035): the restrictions themselves, and Document Properties ▸ // Security, stay as they are. let secured = show_secured_notice && doc.security_summary().is_some_and(|s| !(s.owner || (s.permissions.modify() && s.permissions.assemble()))); let repaired = !doc.repair_log().is_empty(); - let notice = notices(view, doc, secured, repaired, crate::sign_ui::banner(&doc.signatures), ui, &t); + let notice = notices(view, doc, secured, repaired, lock_offer, crate::sign_ui::banner(&doc.signatures), ui, &t); apply_notice(app, index, notice); let Some(doc) = app.session.get(app.views[index].id) else { return }; let info = &doc.info; diff --git a/crates/ui-egui/src/canvas/bars.rs b/crates/ui-egui/src/canvas/bars.rs index 4ad2bf05db..9d488721f5 100644 --- a/crates/ui-egui/src/canvas/bars.rs +++ b/crates/ui-egui/src/canvas/bars.rs @@ -59,16 +59,20 @@ pub(super) enum Notice { Close, /// Stop showing the secured-document notice, in every document (#4035). HideSecured, + /// Lock the placed signatures into the page (#2149). + LockSignatures, } /// The notice bar above the pages: a file changed on disk first, then what a historical -/// snapshot is, then the signature status bar, a form's scripts having been turned -/// off, security, forms and warnings. +/// snapshot is, then the offer to lock a signature just placed, then the signature status bar, +/// a form's scripts having been turned off, security, forms and warnings. +#[allow(clippy::too_many_arguments)] pub(super) fn notices( view: &mut DocView, doc: &pdfcraft_engine::Document, secured: bool, repaired: bool, + lock_offer: bool, signed: Option<(&str, Color32, &str, String)>, ui: &mut egui::Ui, t: &Tokens, @@ -122,6 +126,22 @@ pub(super) fn notices( return Some(Notice::Close); } } + // A signature just placed with Fill & Sign is a comment others can move (#2149): offer to + // lock it into the page now. `lock_offer` is false for a digitally signed document. + if lock_offer && !view.lock_offer_dismissed { + let mut lock = false; + notice_bar(ui, t, "lock", t.accent_text, tl!("Signature added. Others can move it until it's locked.").to_string(), |ui| { + if icons::button(ui, "x", 22.0, false, tl!("Dismiss")).clicked() { + view.lock_offer_dismissed = true; + } + if crate::widgets::pill_button(ui, tl!("Lock now"), true).clicked() { + lock = true; + } + }); + if lock { + return Some(Notice::LockSignatures); + } + } if let Some((icon, color, template, arg)) = signed { let mut open = false; notice_bar(ui, t, icon, color, crate::i18n::fmt(tl!(template), &[("by", &arg)]), |ui| { diff --git a/crates/ui-egui/src/editing.rs b/crates/ui-egui/src/editing.rs index f753335b72..c97cf934d4 100644 --- a/crates/ui-egui/src/editing.rs +++ b/crates/ui-egui/src/editing.rs @@ -478,6 +478,11 @@ impl PdfCraftApp { } } Some(crate::canvas::ViewAction::CameraLevel) => self.camera_level(i), + Some(crate::canvas::ViewAction::LockSignatures) => { + if let Some(id) = self.views.get(i).map(|v| v.id) { + self.lock_signatures_now(id); + } + } Some(crate::canvas::ViewAction::CameraNext(command)) => { self.leave_camera(i); self.execute(command); @@ -681,6 +686,10 @@ impl PdfCraftApp { && let Some(id) = doc_id { self.placed_signatures.insert(id); + // A new signature shows the Lock now notice again, even if the last was dismissed. + if let Some(view) = self.views.get_mut(i) { + view.lock_offer_dismissed = false; + } } // Tab can wrap to the same field (including another widget of that field). // Its new editor was opened before this edit ran, so it still holds the old diff --git a/crates/ui-egui/src/editing/save.rs b/crates/ui-egui/src/editing/save.rs index 0ab9bd5b5d..131cb815e1 100644 --- a/crates/ui-egui/src/editing/save.rs +++ b/crates/ui-egui/src/editing/save.rs @@ -183,18 +183,8 @@ impl PdfCraftApp { /// 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 }; - 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) { - self.notify_error(e); - return; - } - if before != self.session.get(p.id).map(|d| d.edit_generation()) - && let Some(doc) = self.session.get(p.id) - && let Some(view) = self.views.iter_mut().find(|v| v.id == p.id) - { - view.document_changed(&doc.info); - } + if lock && !self.flatten_fill_sign_on_save && !self.flatten_fill_sign_in(p.id) { + return; } self.placed_signatures.remove(&p.id); if remember { @@ -209,6 +199,37 @@ impl PdfCraftApp { } } + /// Lock now, on the notice shown after a signature is placed (#2149): lock document `id`'s + /// Fill & Sign marks into its pages, as the save-time question's Lock does but without + /// saving. Undoable. The next save doesn't ask, as no Fill & Sign mark is left to lock; the + /// placed-signature mark itself stays, so undoing the lock brings back both the notice and the + /// save-time question. Never on a digitally signed document. + pub(crate) fn lock_signatures_now(&mut self, id: pdfcraft_engine::DocId) { + if self.session.get(id).is_none_or(|d| d.is_signed()) { + return; + } + if self.flatten_fill_sign_in(id) { + self.notify_tr("Signature locked into the page."); + } + } + + /// Lock document `id`'s Fill & Sign marks into its pages (an undoable edit). Returns false, + /// having told the user why, when that fails. + fn flatten_fill_sign_in(&mut self, id: pdfcraft_engine::DocId) -> bool { + let before = self.session.get(id).map(|d| d.edit_generation()); + if let Err(e) = self.session.apply(id, pdfcraft_engine::Edit::FlattenFillSign) { + self.notify_error(e); + return false; + } + if before != self.session.get(id).map(|d| d.edit_generation()) + && let Some(doc) = self.session.get(id) + && let Some(view) = self.views.iter_mut().find(|v| v.id == id) + { + view.document_changed(&doc.info); + } + true + } + /// Write document `id` to `dest` and make it the document's file. Returns `true` if written. #[cfg(not(target_arch = "wasm32"))] fn save_doc_to(&mut self, id: pdfcraft_engine::DocId, dest: &str, target: SaveTarget) -> bool { diff --git a/crates/ui-egui/src/i18n/ar.tsv b/crates/ui-egui/src/i18n/ar.tsv index 746e20477d..bec6e3aad6 100644 --- a/crates/ui-egui/src/i18n/ar.tsv +++ b/crates/ui-egui/src/i18n/ar.tsv @@ -2286,6 +2286,9 @@ calendar date December ديسمبر Keep editable إبقاؤه قابلًا للتحرير Lock into the page when saving التثبيت في الصفحة عند الحفظ Otherwise, ask on the first save after a signature is placed وإلا فاسأل عند أول حفظ بعد وضع توقيع + Signature added. Others can move it until it's locked. تمت إضافة التوقيع. يمكن للآخرين نقله إلى أن يتم تثبيته. + Lock now التثبيت الآن + Signature locked into the page. تم تثبيت التوقيع في الصفحة. Text, marks and signatures become part of the page. Other comments stay editable. النص والعلامات والتوقيعات تصبح جزءًا من الصفحة. التعليقات الأخرى تبقى قابلة للتحرير. Date format تنسيق التاريخ Fill & Sign dates تواريخ التعبئة والتوقيع diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index 516fbb62c9..47abedb819 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -146,6 +146,9 @@ Keep editable Да остане редактируем Lock into the page when saving Заключване в страницата при запис Otherwise, ask on the first save after a signature is placed Иначе питай при първия запис след поставяне на подпис + Signature added. Others can move it until it's locked. Подписът е добавен. Други могат да го преместват, докато не бъде заключен. + Lock now Заключи сега + Signature locked into the page. Подписът е заключен в страницата. Text, marks and signatures become part of the page. Other comments stay editable. Текстът, маркировките и подписите стават част от страницата. Другите коментари остават редактируеми. OK OK Cancel Отказ diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 805b9c1885..61bba6af53 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -2307,6 +2307,9 @@ calendar date December prosince Keep editable Ponechat upravitelné Lock into the page when saving Při ukládání zamknout do stránky Otherwise, ask on the first save after a signature is placed Jinak se zeptat při prvním uložení po umístění podpisu + Signature added. Others can move it until it's locked. Podpis byl přidán. Ostatní ho mohou přesouvat, dokud nebude zamčen. + Lock now Zamknout nyní + Signature locked into the page. Podpis byl zamčen do stránky. Text, marks and signatures become part of the page. Other comments stay editable. Text, značky a podpisy se stanou součástí stránky. Ostatní komentáře zůstanou upravitelné. Date format Formát data Fill & Sign dates Datum pro Vyplnit a podepsat diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index 2a4a5b4e0e..c0fcca266e 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -79,6 +79,9 @@ Keep editable Bearbeitbar lassen Lock into the page when saving Beim Speichern fest in die Seite übernehmen Otherwise, ask on the first save after a signature is placed Andernfalls beim ersten Speichern nach dem Platzieren einer Unterschrift fragen + Signature added. Others can move it until it's locked. Unterschrift hinzugefügt. Andere können sie verschieben, bis sie fest übernommen ist. + Lock now Jetzt übernehmen + Signature locked into the page. Unterschrift fest in die Seite übernommen. Text, marks and signatures become part of the page. Other comments stay editable. Text, Markierungen und Unterschriften werden Teil der Seite. Andere Kommentare bleiben bearbeitbar. OK OK Join our Discord Unserem Discord beitreten diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index 6e031b4e4f..83bd80433d 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -294,6 +294,9 @@ Keep editable Να παραμείνει επεξεργάσιμη Lock into the page when saving Κλείδωμα στη σελίδα κατά την αποθήκευση Otherwise, ask on the first save after a signature is placed Διαφορετικά, ερώτηση στην πρώτη αποθήκευση μετά την τοποθέτηση υπογραφής + Signature added. Others can move it until it's locked. Η υπογραφή προστέθηκε. Άλλοι μπορούν να τη μετακινήσουν μέχρι να κλειδωθεί. + Lock now Κλείδωμα τώρα + Signature locked into the page. Η υπογραφή κλειδώθηκε στη σελίδα. Text, marks and signatures become part of the page. Other comments stay editable. Το κείμενο, τα σημάδια και οι υπογραφές γίνονται μέρος της σελίδας. Τα υπόλοιπα σχόλια παραμένουν επεξεργάσιμα. Current page — type a page number or label (such as iv) and press Enter Τρέχουσα σελίδα — πληκτρολογήστε αριθμό ή ετικέτα σελίδας (π.χ. iv) και πατήστε Enter Zoom — type a percentage and press Enter Ζουμ — πληκτρολογήστε ένα ποσοστό και πατήστε Enter diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 10897567ac..90670ed8c3 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -102,6 +102,9 @@ Keep editable Mantener editable Lock into the page when saving Fijar en la página al guardar Otherwise, ask on the first save after a signature is placed Si no, preguntar al guardar por primera vez tras colocar una firma + Signature added. Others can move it until it's locked. Firma añadida. Otros pueden moverla hasta que se fije. + Lock now Fijar ahora + Signature locked into the page. Firma fijada en la página. Text, marks and signatures become part of the page. Other comments stay editable. El texto, las marcas y las firmas pasan a formar parte de la página. Los demás comentarios siguen siendo editables. OK Aceptar Join our Discord Únete a nuestro Discord diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 0c4572fe22..ec03bf9065 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -79,6 +79,9 @@ Keep editable Garder modifiable Lock into the page when saving Intégrer à la page à l’enregistrement Otherwise, ask on the first save after a signature is placed Sinon, demander au premier enregistrement après avoir placé une signature + Signature added. Others can move it until it's locked. Signature ajoutée. D’autres peuvent la déplacer tant qu’elle n’est pas intégrée. + Lock now Intégrer maintenant + Signature locked into the page. Signature intégrée à la page. Text, marks and signatures become part of the page. Other comments stay editable. Le texte, les marques et les signatures deviennent partie de la page. Les autres commentaires restent modifiables. OK OK Join our Discord Rejoindre notre Discord diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index 7a066c9ba3..62bdec8418 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -2263,6 +2263,9 @@ action wizard Start Indítás Keep editable Szerkeszthető marad Lock into the page when saving Mentéskor rögzítés az oldalba Otherwise, ask on the first save after a signature is placed Különben kérdezzen rá az aláírás elhelyezése utáni első mentéskor + Signature added. Others can move it until it's locked. Aláírás hozzáadva. Mások áthelyezhetik, amíg nincs rögzítve. + Lock now Rögzítés most + Signature locked into the page. Az aláírás rögzítve az oldalba. Text, marks and signatures become part of the page. Other comments stay editable. A szöveg, a jelek és az aláírások az oldal részévé válnak. A többi megjegyzés szerkeszthető marad. Date format Dátumformátum Fill & Sign dates Kitöltés és aláírás dátumai diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index ae3ebd6693..cb4af09c53 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -2223,6 +2223,9 @@ Keep editable Mantieni modificabile Lock into the page when saving Blocca nella pagina al salvataggio Otherwise, ask on the first save after a signature is placed Altrimenti, chiedi al primo salvataggio dopo aver inserito una firma + Signature added. Others can move it until it's locked. Firma aggiunta. Altri possono spostarla finché non viene bloccata. + Lock now Blocca ora + Signature locked into the page. Firma bloccata nella pagina. H / Space (hold) H / Spazio (tieni premuto) Home / End Home / Fine Inserted text Testo inserito diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index ddeb261438..bb485aa589 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -2278,6 +2278,9 @@ signature pad Type 入力 Keep editable 編集可能のままにする Lock into the page when saving 保存時にページに固定 Otherwise, ask on the first save after a signature is placed それ以外は、署名を配置した後の最初の保存時に確認する + Signature added. Others can move it until it's locked. 署名を追加しました。固定するまでは他の人が移動できます。 + Lock now 今すぐ固定 + Signature locked into the page. 署名をページに固定しました。 Text, marks and signatures become part of the page. Other comments stay editable. テキスト、マーク、署名がページの一部になります。その他のコメントは引き続き編集できます。 Scroll tabs left タブを左にスクロール Scroll tabs right タブを右にスクロール diff --git a/crates/ui-egui/src/i18n/kk.tsv b/crates/ui-egui/src/i18n/kk.tsv index 8171e1cac4..01cd4375f2 100644 --- a/crates/ui-egui/src/i18n/kk.tsv +++ b/crates/ui-egui/src/i18n/kk.tsv @@ -2195,6 +2195,9 @@ calendar date December Желтоқсан Keep editable Өңделетін күйде қалдыру Lock into the page when saving Сақтағанда бетке бекіту Otherwise, ask on the first save after a signature is placed Әйтпесе, қолтаңба қойылғаннан кейінгі алғашқы сақтауда сұрау + Signature added. Others can move it until it's locked. Қолтаңба қосылды. Ол бекітілгенше басқалар оны жылжыта алады. + Lock now Қазір бекіту + Signature locked into the page. Қолтаңба бетке бекітілді. Text, marks and signatures become part of the page. Other comments stay editable. Мәтін, белгілер мен қолтаңбалар беттің бөлігіне айналады. Басқа түсініктемелер өңделетін күйде қалады. Date format Күн пішімі Fill & Sign dates «Толтыру және қол қою» күндері diff --git a/crates/ui-egui/src/i18n/lt.tsv b/crates/ui-egui/src/i18n/lt.tsv index d93109274e..20fa9230c7 100644 --- a/crates/ui-egui/src/i18n/lt.tsv +++ b/crates/ui-egui/src/i18n/lt.tsv @@ -598,6 +598,9 @@ Keep editable Palikti redaguojamą Lock into the page when saving Įrašant įtvirtinti puslapyje Otherwise, ask on the first save after a signature is placed Kitaip klausti pirmą kartą įrašant po parašo padėjimo + Signature added. Others can move it until it's locked. Parašas pridėtas. Kiti gali jį perkelti, kol jis neįtvirtintas. + Lock now Įtvirtinti dabar + Signature locked into the page. Parašas įtvirtintas puslapyje. Flip Horizontal Apversti horizontaliai Flip Vertical Apversti vertikaliai Flip horizontal Apversti horizontaliai diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index f071c3cda3..9a7a5f0089 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -2257,6 +2257,9 @@ signature pad Type Wpisz Keep editable Zachowaj edytowalny Lock into the page when saving Utrwalaj na stronie przy zapisie Otherwise, ask on the first save after a signature is placed W przeciwnym razie pytaj przy pierwszym zapisie po umieszczeniu podpisu + Signature added. Others can move it until it's locked. Dodano podpis. Inni mogą go przesunąć, dopóki nie zostanie utrwalony. + Lock now Utrwal teraz + Signature locked into the page. Podpis utrwalono na stronie. Text, marks and signatures become part of the page. Other comments stay editable. Tekst, oznaczenia i podpisy stają się częścią strony. Pozostałe komentarze pozostają edytowalne. Scroll tabs left Przewiń karty w lewo Scroll tabs right Przewiń karty w prawo diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index eae76f0a35..5f143e88b7 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -2216,6 +2216,9 @@ action wizard Start Iniciar Keep editable Manter editável Lock into the page when saving Fixar na página ao salvar Otherwise, ask on the first save after a signature is placed Caso contrário, perguntar ao salvar pela primeira vez após colocar uma assinatura + Signature added. Others can move it until it's locked. Assinatura adicionada. Outras pessoas podem movê-la até que seja fixada. + Lock now Fixar agora + Signature locked into the page. Assinatura fixada na página. H / Space (hold) H / Espaço (manter pressionado) Home / End Home / End Inserted text Texto inserido diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 0b5274603c..0545896c55 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -99,6 +99,9 @@ Keep editable Оставить редактируемой Lock into the page when saving Закреплять на странице при сохранении Otherwise, ask on the first save after a signature is placed Иначе спрашивать при первом сохранении после размещения подписи + Signature added. Others can move it until it's locked. Подпись добавлена. Другие могут перемещать её, пока она не закреплена. + Lock now Закрепить сейчас + Signature locked into the page. Подпись закреплена на странице. Text, marks and signatures become part of the page. Other comments stay editable. Текст, пометки и подписи становятся частью страницы. Остальные комментарии можно по-прежнему править. OK OK Join our Discord Присоединяйтесь к нашему Discord diff --git a/crates/ui-egui/src/i18n/sl.tsv b/crates/ui-egui/src/i18n/sl.tsv index 41286d281a..c938b17fbc 100644 --- a/crates/ui-egui/src/i18n/sl.tsv +++ b/crates/ui-egui/src/i18n/sl.tsv @@ -2211,6 +2211,9 @@ signature pad Type Vtipkaj Keep editable Ohrani urejljivo Lock into the page when saving Ob shranjevanju zakleni v stran Otherwise, ask on the first save after a signature is placed Sicer vprašaj ob prvem shranjevanju po postavitvi podpisa + Signature added. Others can move it until it's locked. Podpis je dodan. Drugi ga lahko premaknejo, dokler ni zaklenjen. + Lock now Zakleni zdaj + Signature locked into the page. Podpis je zaklenjen v stran. Font size 0 uses automatic sizing. Velikost pisave 0 pomeni samodejno velikost. Import list… Uvozi seznam… Larger pages Večje strani diff --git a/crates/ui-egui/src/i18n/te.tsv b/crates/ui-egui/src/i18n/te.tsv index 0082655ae8..4d08bfa192 100644 --- a/crates/ui-egui/src/i18n/te.tsv +++ b/crates/ui-egui/src/i18n/te.tsv @@ -2511,6 +2511,9 @@ animation effects Off ఆఫ్ Keep editable సవరించగలిగేలా ఉంచు Lock into the page when saving సేవ్ చేసేటప్పుడు పేజీలో లాక్ చేయి Otherwise, ask on the first save after a signature is placed లేకపోతే, సంతకం ఉంచిన తర్వాత మొదటి సేవ్‌లో అడుగు + Signature added. Others can move it until it's locked. సంతకం జోడించబడింది. లాక్ చేసే వరకు ఇతరులు దానిని తరలించగలరు. + Lock now ఇప్పుడే లాక్ చేయి + Signature locked into the page. సంతకం పేజీలో లాక్ చేయబడింది. # Date picker: Today button (#4274) (AI-assisted, not separately native-reviewed) Today ఈరోజు diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index d40032efa8..20ab89ee2b 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -70,6 +70,9 @@ Keep editable Düzenlenebilir bırak Lock into the page when saving Kaydederken sayfaya sabitle Otherwise, ask on the first save after a signature is placed Aksi halde, imza yerleştirildikten sonraki ilk kayıtta sor + Signature added. Others can move it until it's locked. İmza eklendi. Sabitlenene kadar başkaları onu taşıyabilir. + Lock now Şimdi sabitle + Signature locked into the page. İmza sayfaya sabitlendi. Text, marks and signatures become part of the page. Other comments stay editable. Metin, işaretler ve imzalar sayfanın bir parçası olur. Diğer yorumlar düzenlenebilir kalır. OK Tamam Join our Discord Discord'umuza katılın diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index 30c8000fc8..3c181c5b2b 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -2286,6 +2286,9 @@ calendar date December грудня Keep editable Залишити редагованим Lock into the page when saving Закріплювати на сторінці під час збереження Otherwise, ask on the first save after a signature is placed Інакше питати під час першого збереження після розміщення підпису + Signature added. Others can move it until it's locked. Підпис додано. Інші можуть переміщувати його, доки його не закріплено. + Lock now Закріпити зараз + Signature locked into the page. Підпис закріплено на сторінці. Text, marks and signatures become part of the page. Other comments stay editable. Текст, позначки й підписи стають частиною сторінки. Інші коментарі залишаються редагованими. Date format Формат дати Fill & Sign dates Дати заповнення й підпису diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index 2275b4b78a..095c6e8832 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -2894,3 +2894,6 @@ key Space Space Lock into the page when saving Khóa vào trang khi lưu Lock your signature into the page? Khóa chữ ký của bạn vào trang? Otherwise, ask on the first save after a signature is placed Nếu không, hỏi ở lần lưu đầu tiên sau khi đặt chữ ký + Signature added. Others can move it until it's locked. Đã thêm chữ ký. Người khác có thể di chuyển nó cho đến khi được khóa. + Lock now Khóa ngay + Signature locked into the page. Đã khóa chữ ký vào trang. diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index c5c7918373..9959eb8a7e 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -152,6 +152,9 @@ Keep editable 保持可编辑 Lock into the page when saving 保存时锁定到页面 Otherwise, ask on the first save after a signature is placed 否则,在放置签名后首次保存时询问 + Signature added. Others can move it until it's locked. 已添加签名。锁定之前,其他人可以移动它。 + Lock now 立即锁定 + Signature locked into the page. 签名已锁定到页面。 Text, marks and signatures become part of the page. Other comments stay editable. 文字、标记和签名会成为页面内容。其他注释仍可编辑。 OK 确定 Cancel 取消 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index 9ef514a3b5..4f5a08dcbd 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -2552,6 +2552,9 @@ animation effects Off 關 Keep editable 保持可編輯 Lock into the page when saving 儲存時鎖定到頁面 Otherwise, ask on the first save after a signature is placed 否則,在放置簽名後第一次儲存時詢問 + Signature added. Others can move it until it's locked. 已加入簽名。鎖定之前,其他人可以移動它。 + Lock now 立即鎖定 + Signature locked into the page. 簽名已鎖定到頁面。 # Date picker: Today button (#4274) (AI-assisted, not separately native-reviewed) Today 今天 diff --git a/crates/ui-egui/src/panels/tools.rs b/crates/ui-egui/src/panels/tools.rs index 73326fe571..6ab469e123 100644 --- a/crates/ui-egui/src/panels/tools.rs +++ b/crates/ui-egui/src/panels/tools.rs @@ -291,6 +291,9 @@ fn tool_detail(app: &mut PdfCraftApp, ui: &mut egui::Ui, t: &Tokens, g: &'static if let Some(cmd) = crate::fill_sign::signature_entries(ui, app, t) { run = Some(cmd); } + // Where the signing happens, not only in Preferences, and once: not also in the Sign + // menu over the page, where it was easy to miss (#2149). + ui.add(widgets::checkbox(&mut app.flatten_fill_sign_on_save, tl!("Lock into the page when saving"))); } }); if footer { diff --git a/crates/ui-egui/src/tools/fill_sign.rs b/crates/ui-egui/src/tools/fill_sign.rs index 225faca601..045bb64974 100644 --- a/crates/ui-egui/src/tools/fill_sign.rs +++ b/crates/ui-egui/src/tools/fill_sign.rs @@ -398,8 +398,6 @@ pub(crate) fn signature_entries(ui: &mut egui::Ui, app: &mut crate::PdfCraftApp, }); ui.add_space(4.0); } - // Where the signing happens, not only in Preferences (#2149). - ui.add(crate::widgets::checkbox(&mut app.flatten_fill_sign_on_save, tl!("Lock into the page when saving"))); command } diff --git a/crates/ui-egui/tests/it/fill_sign.rs b/crates/ui-egui/tests/it/fill_sign.rs index 3c7eb8a0d8..733fed5bde 100644 --- a/crates/ui-egui/tests/it/fill_sign.rs +++ b/crates/ui-egui/tests/it/fill_sign.rs @@ -1754,7 +1754,8 @@ fn photos_and_images_dropped_on_the_signature_pad_are_imported_not_opened() { /// #2149: the first save after Fill & Sign places a signature asks whether to lock it into the /// page. Lock and save flattens it; Keep editable keeps it a comment; Don't ask again becomes -/// the preference; the Sign menu has the switch too. +/// the preference; the Fill & Sign panel has the switch too, once, and the Sign menu no longer +/// does (review on #2348). #[test] fn the_first_save_after_placing_a_signature_asks_to_lock_it() { let out = std::env::temp_dir().join(format!("pdfcraft-lock-signature-{}.pdf", std::process::id())); @@ -1790,18 +1791,110 @@ fn the_first_save_after_placing_a_signature_asks_to_lock_it() { assert_eq!(signed(&h), 0, "locked into the page"); assert!(!h.state().session.get(h.state().views[0].id).unwrap().dirty); assert!(h.state().flatten_fill_sign_on_save, "remembered as the preference"); - // The Sign menu shows the same switch. + // The switch is in the panel's Sign yourself section, once; the Sign menu over the page, + // where it was easy to miss, no longer has it. h.state_mut().flatten_fill_sign_on_save = false; h.get_by_label("Fill & Sign").click(); h.run_steps(2); h.get_by_label("Fill & Sign").click(); h.run_steps(2); + h.get_by_label("Use signature"); + assert!(h.query_by_label("Lock into the page when saving").is_none(), "not in the Sign menu"); + h.key_press(egui::Key::Escape); + h.run_steps(2); + assert!(h.query_by_label("Lock into the page when saving").is_none(), "the panel is closed"); + h.state_mut().left = pdfcraft_ui_egui::LeftPanel::Tool("fill_sign"); + h.state_mut().left_open = true; + h.run_steps(3); + h.get_by_label("Use signature"); + assert_eq!(h.query_all_by_label("Lock into the page when saving").count(), 1, "once, in the panel"); h.get_by_label("Lock into the page when saving").click(); h.run_steps(2); assert!(h.state().flatten_fill_sign_on_save); let _ = std::fs::remove_file(&out); } +/// #2348 review (benandez): right after a signature is placed, a notice offers to lock it into +/// the page now. Lock now flattens it (undoable) without saving, so the save that follows doesn't +/// ask; undoing the lock brings back both the notice and the question. Dismiss hides the notice +/// until the next signature. A digitally signed document, or one whose saves lock anyway, gets no +/// notice. +#[test] +fn placing_a_signature_offers_to_lock_it_now() { + const NOTICE: &str = "Signature added. Others can move it until it's locked."; + let out = std::env::temp_dir().join(format!("pdfcraft-lock-now-{}.pdf", std::process::id())); + let place = |h: &mut Harness<'static, PdfCraftApp>, y: f32| { + h.state_mut().signature = Some(SavedSig::Typed("Ada Lovelace".into())); + h.state_mut().execute("sign.fill.signature"); + h.run_steps(2); + click(h, 40.0, y); + h.run_steps(2); + }; + let marks = |h: &Harness<'static, PdfCraftApp>| { + h.state().session.get(h.state().views[0].id).unwrap().info.annotations.iter().filter(|a| a.fill_sign).count() + }; + let mut h = harness(); + h.state_mut().save_override = Some(out.to_string_lossy().into_owned()); + assert!(h.query_by_label(NOTICE).is_none(), "nothing placed yet"); + place(&mut h, 300.0); + h.get_by_label(NOTICE); + h.get_by_label("Lock now").click(); + h.run_steps(3); + assert_eq!(marks(&h), 0, "locked into the page"); + assert!(h.query_by_label(NOTICE).is_none(), "nothing left to lock"); + assert!(h.state().session.get(h.state().views[0].id).unwrap().dirty, "locked, not saved"); + // Undo brings the movable signature back, with the notice and the save-time question. + assert!(h.state_mut().execute("edit.undo")); + h.run_steps(3); + assert_eq!(marks(&h), 1); + h.get_by_label(NOTICE); + assert!(!h.state_mut().save_active(SaveTarget::InPlace), "asks again after undoing the lock"); + h.run_steps(2); + h.get_by_label("Cancel").click(); + h.run_steps(2); + // Locked again, the save doesn't ask. + h.get_by_label("Lock now").click(); + h.run_steps(3); + assert!(h.state_mut().save_active(SaveTarget::InPlace), "already locked: no question"); + // Dismiss hides it until the next signature. + place(&mut h, 200.0); + h.get_by_label(NOTICE); + h.get_by_label("Dismiss").click(); + h.run_steps(2); + assert!(h.query_by_label(NOTICE).is_none(), "dismissed"); + place(&mut h, 100.0); + h.get_by_label(NOTICE); + // Once saved, a signature kept as a comment is no longer just placed: no notice. + assert!(!h.state_mut().save_active(SaveTarget::InPlace), "asks first"); + h.run_steps(2); + h.get_by_label("Keep editable").click(); + h.run_steps(3); + assert!(marks(&h) > 0, "still a comment"); + assert!(h.query_by_label(NOTICE).is_none(), "saved: nothing just placed"); + place(&mut h, 50.0); + h.get_by_label(NOTICE); + // Saves that lock anyway need no offer. + h.state_mut().flatten_fill_sign_on_save = true; + h.run_steps(2); + assert!(h.query_by_label(NOTICE).is_none(), "saving locks it anyway"); + let _ = std::fs::remove_file(&out); + + // Digitally signed: no notice, as locking would change the document after signing. + let mut doc = { + let mut h = harness(); + let app = h.state_mut(); + let id = app.views[0].id; + let p12 = std::fs::read(concat!(env!("CARGO_MANIFEST_DIR"), "/../sign/tests/data/ec-p256.p12")).unwrap(); + let digital_id = pdfcraft_engine::sign::pkcs12::open(&p12, "test").unwrap(); + let opts = pdfcraft_engine::SignOptions { page: 0, rect: Some([20.0, 20.0, 160.0, 50.0]), ..Default::default() }; + app.session.sign(id, &digital_id, opts).expect("signs") + }; + let mut h = harness_bytes(&std::mem::take(&mut doc)); + place(&mut h, 300.0); + assert_eq!(marks(&h), 1); + assert!(h.query_by_label(NOTICE).is_none(), "a signed document isn't offered the lock"); +} + /// #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. diff --git a/parity/acrobat-features.toml b/parity/acrobat-features.toml index cd0c858371..bec5d3568f 100644 --- a/parity/acrobat-features.toml +++ b/parity/acrobat-features.toml @@ -5441,8 +5441,8 @@ milestone = "M5" status = "shipped" commands = ["comment.flatten"] tools = ["doc_save", "doc_flatten"] -evidence = ["crates/edit/src/tests.rs::fill_sign_flatten_bakes_marks_keeps_other_comments_and_does_not_reuse_pcfl0", "crates/engine/src/tests.rs::flattening_fill_and_sign_keeps_other_comments_fields_and_undoes", "crates/engine/src/tests.rs::flattening_fill_and_sign_is_refused_without_permission_to_change", "crates/automation/tests/it/automation.rs::saving_with_flatten_fill_sign_bakes_marks_and_leaves_other_comments", "crates/ui-egui/tests/it/fill_sign.rs::saving_flattens_fill_and_sign_only_when_the_preference_is_on", "crates/ui-egui/tests/it/fill_sign.rs::the_first_save_after_placing_a_signature_asks_to_lock_it", "crates/ui-egui/tests/it/fill_sign.rs::cancelling_the_lock_question_saves_nothing", "crates/ui-egui/tests/it/fill_sign.rs::a_lock_that_fails_keeps_the_question", "crates/ui-egui/tests/it/fill_sign.rs::the_lock_question_is_skipped_or_kept_where_it_must_be"] -notes = "Preferences ▸ Fill & Sign, and doc_save flatten_fill_sign, bake text, marks and signatures into the page. The option defaults off, so a normal save leaves them editable; the first save after a signature or initials is placed asks whether to lock it into the page (Lock and save / Keep editable, with Don't ask again), and the Sign menu carries the same switch (#2149). Other comments and form fields stay. Flatten comments still flattens every comment." +evidence = ["crates/edit/src/tests.rs::fill_sign_flatten_bakes_marks_keeps_other_comments_and_does_not_reuse_pcfl0", "crates/engine/src/tests.rs::flattening_fill_and_sign_keeps_other_comments_fields_and_undoes", "crates/engine/src/tests.rs::flattening_fill_and_sign_is_refused_without_permission_to_change", "crates/automation/tests/it/automation.rs::saving_with_flatten_fill_sign_bakes_marks_and_leaves_other_comments", "crates/ui-egui/tests/it/fill_sign.rs::saving_flattens_fill_and_sign_only_when_the_preference_is_on", "crates/ui-egui/tests/it/fill_sign.rs::placing_a_signature_offers_to_lock_it_now", "crates/ui-egui/tests/it/fill_sign.rs::the_first_save_after_placing_a_signature_asks_to_lock_it", "crates/ui-egui/tests/it/fill_sign.rs::cancelling_the_lock_question_saves_nothing", "crates/ui-egui/tests/it/fill_sign.rs::a_lock_that_fails_keeps_the_question", "crates/ui-egui/tests/it/fill_sign.rs::the_lock_question_is_skipped_or_kept_where_it_must_be"] +notes = "Preferences ▸ Fill & Sign, and doc_save flatten_fill_sign, bake text, marks and signatures into the page. The option defaults off, so a normal save leaves them editable; right after a signature or initials is placed, a notice offers Lock now (undoable, no save), and the first save after one is placed asks whether to lock it into the page (Lock and save / Keep editable, with Don't ask again); the Fill & Sign panel's Sign yourself section carries the same switch (#2149). Not on a digitally signed document. Other comments and form fields stay. Flatten comments still flattens every comment." [[feature]] id = "form.autofill-profile"