mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-27 03:27:21 -06:00
This commit is contained in:
@@ -1838,6 +1838,57 @@ mod tests {
|
||||
assert!(app.views[0].line_editor.is_some(), "the paragraph stays open for editing");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn save_applies_the_paragraph_open_in_the_editor() {
|
||||
// Save wrote the file without the paragraph still open in the editor (#3496).
|
||||
let (mut app, mut ed) = preview_app();
|
||||
ed.text = "Text preview".into();
|
||||
app.views[0].line_editor = Some(ed);
|
||||
let dir = std::env::temp_dir().join(format!("pdfcraft-ui-open-paragraph-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
app.save_override = Some(dir.join("out.pdf").to_string_lossy().into_owned());
|
||||
|
||||
assert!(app.save_active(crate::SaveTarget::InPlace));
|
||||
assert!(app.views[0].line_editor.is_none());
|
||||
let doc = app.session.get(app.views[0].id).unwrap();
|
||||
assert_eq!(doc.text_lines(0).iter().map(|l| l.text.as_str()).collect::<String>(), "Text preview");
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_refused_text_box_does_not_lose_the_open_paragraph() {
|
||||
let (mut app, mut ed) = preview_app();
|
||||
ed.text = "Text preview".into();
|
||||
app.views[0].line_editor = Some(ed);
|
||||
let draft = crate::content_ui::TextDraft {
|
||||
page: 9,
|
||||
index: None,
|
||||
rect: [20.0, 20.0, 120.0, 40.0],
|
||||
text: "Typed text".into(),
|
||||
style: crate::content_ui::default_style(),
|
||||
focus: true,
|
||||
};
|
||||
app.views[0].content.draft = Some(draft.clone());
|
||||
|
||||
assert!(!app.commit_typing_in(app.views[0].id));
|
||||
assert_eq!(app.views[0].content.draft, Some(draft), "the refused text box stays open");
|
||||
assert!(app.views[0].line_editor.is_none(), "the paragraph was applied");
|
||||
let doc = app.session.get(app.views[0].id).unwrap();
|
||||
assert_eq!(doc.text_lines(0).iter().map(|l| l.text.as_str()).collect::<String>(), "Text preview");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_refused_paragraph_stays_open_with_its_text() {
|
||||
let (mut app, mut ed) = preview_app();
|
||||
ed.text = "Text preview".into();
|
||||
ed.page = 9;
|
||||
app.views[0].line_editor = Some(ed.clone());
|
||||
|
||||
assert!(!app.commit_typing_in(app.views[0].id));
|
||||
assert_eq!(app.views[0].line_editor, Some(ed), "the paragraph keeps its unsaved text");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn text_background_is_cached_without_editing_and_released_on_cancel() {
|
||||
let (app, ed) = preview_app();
|
||||
|
||||
@@ -537,17 +537,44 @@ impl PdfCraftApp {
|
||||
self.notify(crate::content_ui::undrawable_message(c));
|
||||
return false;
|
||||
}
|
||||
let typing = self
|
||||
.views
|
||||
.get(i)
|
||||
.is_some_and(|v| v.pending_edit.is_some() || v.forms.focus.is_some() || v.fill_text.as_ref().is_some_and(|t| !t.text.trim().is_empty()));
|
||||
let typing = self.views.get(i).is_some_and(|v| {
|
||||
v.pending_edit.is_some()
|
||||
|| v.forms.focus.is_some()
|
||||
|| v.content.draft.is_some()
|
||||
|| v.line_editor.as_ref().is_some_and(|ed| ed.has_changes())
|
||||
|| v.fill_text.as_ref().is_some_and(|t| !t.text.trim().is_empty())
|
||||
});
|
||||
if self.active != Some(i) {
|
||||
if !typing {
|
||||
return true;
|
||||
}
|
||||
self.active = Some(i);
|
||||
}
|
||||
self.commit_form_typing() && self.commit_open_fill_text(id)
|
||||
self.commit_form_typing() && self.commit_open_fill_text(id) && self.commit_open_text_edits(id)
|
||||
}
|
||||
|
||||
/// The Edit a PDF ▸ Text boxes (new text, and a paragraph open for editing) commit on
|
||||
/// click-away. Save does that first, so the typed text is in the file instead of being left
|
||||
/// open on the screen (#3496).
|
||||
fn commit_open_text_edits(&mut self, id: pdfcraft_engine::DocId) -> bool {
|
||||
let Some(doc) = self.session.get(id) else { return true };
|
||||
let Some(view) = self.views.iter_mut().find(|v| v.id == id) else { return true };
|
||||
// Both are taken out of the view before either edit runs, so keep what is needed to put
|
||||
// back whichever one the document refuses: typed text must not be lost.
|
||||
let (draft, select_added, editor) = (view.content.draft.clone(), view.content.select_added, view.line_editor.clone());
|
||||
let added = view.content.finish_draft(doc.added());
|
||||
let paragraph = view.line_editor.take_if(|ed| ed.has_changes()).and_then(crate::edit_text_ui::finished_edit);
|
||||
let added_ok = added.is_none_or(|edit| self.apply_edit(edit));
|
||||
let paragraph_ok = paragraph.is_none_or(|edit| self.apply_edit(edit));
|
||||
if let Some(view) = self.views.iter_mut().find(|v| v.id == id) {
|
||||
if !added_ok {
|
||||
(view.content.draft, view.content.select_added) = (draft, select_added);
|
||||
}
|
||||
if !paragraph_ok {
|
||||
view.line_editor = editor;
|
||||
}
|
||||
}
|
||||
added_ok && paragraph_ok
|
||||
}
|
||||
|
||||
/// The Fill & Sign type box commits on click-away. Save does that first, so the text is in
|
||||
@@ -1474,6 +1501,32 @@ mod tests {
|
||||
out
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn save_commits_the_open_text_box() {
|
||||
let dir = staging_dir("open-text-box");
|
||||
let dest = dir.join("out.pdf");
|
||||
let mut app = crate::PdfCraftApp::new();
|
||||
app.set_option("language", "en").unwrap();
|
||||
app.open_bytes("a.pdf", None, one_page_pdf()).unwrap();
|
||||
app.save_override = Some(dest.to_string_lossy().into_owned());
|
||||
let style = crate::content_ui::default_style();
|
||||
app.views[0].content.draft = Some(crate::content_ui::TextDraft {
|
||||
page: 0,
|
||||
index: None,
|
||||
rect: [20.0, 20.0, 120.0, 40.0],
|
||||
text: "Typed text".into(),
|
||||
style,
|
||||
focus: true,
|
||||
});
|
||||
|
||||
assert!(app.save_active(SaveTarget::InPlace));
|
||||
let id = app.views[0].id;
|
||||
let added = app.session.get(id).unwrap().added();
|
||||
assert_eq!(added.len(), 1, "the open text box was committed before the save");
|
||||
assert!(app.views[0].content.draft.is_none());
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn save_asks_where_to_keep_an_email_attachment_and_leaves_the_temporary_copy_alone() {
|
||||
let dir = staging_dir("mail-temp");
|
||||
|
||||
Reference in New Issue
Block a user