Open: a saved .ai with several artboards restores its document instead of asking for pages

Opening a PDF-compatible .ai (or a PDF saved with Preserve Editing) that has more than one
page showed the Import PDF dialog and imported pages, although the file carries its
VectorCraft document. Opening now restores that document (every artboard and layer) without
asking, as the engine already does when no pages are picked. Placing still asks for the page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
llduyll10 2026-10-09 13:48:37 +07:00
parent c4e20023de
commit 1056a42a56
2 changed files with 39 additions and 1 deletions

View File

@ -114,11 +114,17 @@ pub(super) fn show_preview(ui: &mut egui::Ui, tex: Option<&egui::TextureHandle>,
/// Open `bytes` (or place them with the `file.place` params `place`) through the dialog when the
/// file is a PDF (or `.ai`/`.ait`) with several pages or a password; false when there's nothing to
/// ask (the caller goes on).
/// ask (the caller goes on), including a file that carries its VectorCraft document when opening.
pub fn offer(app: &mut VectorcraftApp, name: &str, bytes: &[u8], path: Option<String>, place: Option<&Value>) -> bool {
if !fileio::detect(name, bytes).is_some_and(|f| matches!(f.id, "pdf" | "ai" | "ait")) {
return false;
}
// A file carrying its VectorCraft document (a saved .ai, or a PDF saved with Preserve Editing)
// opens as that document, every artboard and layer: there are no pages to pick. Placing still
// asks, since a place takes one page.
if place.is_none() && vectorcraft_pdf::editing_with(bytes, None).is_some() {
return false;
}
let (pages, locked) = match vectorcraft_pdf::info(bytes, None) {
Ok(i) if i.pages.len() > 1 => (i.pages.len(), false),
Err(PdfError::NeedsPassword) => (0, true),

View File

@ -165,3 +165,35 @@ fn placing_a_pdf_page_asks_for_the_page_and_crop_box() {
assert!(app.ui.dialog.is_none());
assert_eq!(placed(&app).1.width(), 80.0);
}
/// A saved `.ai` with several artboards carries its VectorCraft document: opening it restores that
/// document (artboards, layers) instead of asking which pages to import.
#[test]
fn opening_a_saved_ai_with_several_artboards_restores_it_without_asking() {
let mut app = app();
app.run("artboard.new", json!({"width": 200, "height": 100, "name": "Second"})).unwrap();
app.run("layer.new", json!({"name": "Front"})).unwrap();
app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 50, "height": 40})).unwrap();
let saved = app.run("document.save", json!({"format": "ai"})).unwrap();
let bytes = vectorcraft_format::base64_decode(saved["dataBase64"].as_str().unwrap()).unwrap();
assert!(vectorcraft_pdf::info(&bytes, None).unwrap().pages.len() > 1, "a page per artboard");
io::open_bytes(&mut app, "two.ai", &bytes, Some("/tmp/two.ai".into())).unwrap();
assert!(app.ui.dialog.is_none(), "no Import PDF dialog");
assert_eq!(app.session.documents().len(), 2);
let doc = &app.session.active().unwrap().doc;
assert_eq!(doc.artboards.len(), 2);
assert_eq!(doc.artboards[1].name, "Second");
assert!(doc.layers.iter().any(|l| l.name.as_deref() == Some("Front")), "layers come back");
}
/// A PDF without a VectorCraft document still asks, and placing a saved `.ai` still asks for the page.
#[test]
fn placing_a_saved_ai_still_asks_for_the_page() {
let mut app = app();
app.run("artboard.new", json!({"width": 200, "height": 100})).unwrap();
let saved = app.run("document.save", json!({"format": "ai"})).unwrap();
let bytes = vectorcraft_format::base64_decode(saved["dataBase64"].as_str().unwrap()).unwrap();
assert!(import_pdf::offer(&mut app, "two.ai", &bytes, None, Some(&json!({}))));
assert_eq!(app.ui.dialog.as_ref().unwrap().str("mode"), "place");
}