feat(commands): add ARCHIVE / ETRANSMIT (folder package)

Package the drawing plus its referenced files (xrefs + raster images)
into a sibling "<name>_archive" folder via std::fs, reusing the
existing block_records / entities iterators. COMMANDS.md: 217/262.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-06-29 09:10:57 +03:00
1 parent f513899d49
commit 6f9565e9f7
3 files changed
+67 -4

No files matched your search

+4 -4
View File
@@ -313,8 +313,8 @@ Status of every standard CAD command in Open CAD Studio:
| `QUIT` | — | Exit application | ✅ |
| `RECOVER` | — | Recover damaged drawing | ❌ |
| `CLOSE` | — | Close drawing | ✅ |
| `ARCHIVE` | — | Archive drawing set | ❌ |
| `ETRANSMIT` | — | Transmit drawing package | ❌ |
| `ARCHIVE` | — | Package drawing + references into a folder | ✅ |
| `ETRANSMIT` | — | Transmittal package (folder) | ✅ |
---
@@ -360,9 +360,9 @@ Status of every standard CAD command in Open CAD Studio:
| 3D Modeling | 27 | 23 | 0 | 4 |
| View & Navigation | 32 | 15 | 8 | 9 |
| Inquiry | 12 | 12 | 0 | 0 |
| File & Plot | 17 | 14 | 0 | 3 |
| File & Plot | 17 | 16 | 0 | 1 |
| Manage & Customize | 22 | 13 | 3 | 6 |
| **Total** | **262** | **215** | **15** | **32** |
| **Total** | **262** | **217** | **15** | **30** |
> Counts include commands listed under more than one category (e.g. `SLICE`, `HELIX`,
> `MINSERT`, `SUBTRACT`/`UNION`/`INTERSECT` appear in both their 2D and 3D groups).
+61
View File
@@ -143,6 +143,67 @@ impl OpenCADStudio {
return Some(Task::done(Message::TabClose(self.active_tab)));
}
// ARCHIVE / ETRANSMIT — package the drawing and its referenced files
// (xrefs + raster images) into a sibling "<name>_archive" folder.
"ARCHIVE" | "ETRANSMIT" => {
use std::path::PathBuf;
if let Some(src) = self.tabs[i].current_path.clone() {
let stem = src
.file_stem()
.map(|s| s.to_string_lossy().into_owned())
.unwrap_or_else(|| "drawing".into());
let parent = src
.parent()
.map(|p| p.to_path_buf())
.unwrap_or_else(|| PathBuf::from("."));
let folder = parent.join(format!("{stem}_archive"));
match std::fs::create_dir_all(&folder) {
Ok(()) => {
let mut copied = 0usize;
if let Some(fname) = src.file_name() {
if std::fs::copy(&src, folder.join(fname)).is_ok() {
copied += 1;
}
}
let mut deps: Vec<String> = Vec::new();
for br in self.tabs[i].scene.document.block_records.iter() {
if !br.xref_path.trim().is_empty() {
deps.push(br.xref_path.clone());
}
}
for e in self.tabs[i].scene.document.entities() {
if let acadrust::EntityType::RasterImage(img) = e {
if !img.file_path.trim().is_empty() {
deps.push(img.file_path.clone());
}
}
}
for d in deps {
let dp = PathBuf::from(&d);
let resolved = if dp.is_absolute() { dp } else { parent.join(&dp) };
if resolved.exists() {
if let Some(fname) = resolved.file_name() {
if std::fs::copy(&resolved, folder.join(fname)).is_ok() {
copied += 1;
}
}
}
}
self.command_line.push_output(&format!(
"{cmd}: packaged {copied} file(s) into {}",
folder.display()
));
}
Err(e) => self
.command_line
.push_error(&format!("{cmd}: cannot create folder ({e}).")),
}
} else {
self.command_line
.push_error("ARCHIVE: save the drawing first (it has no file path yet).");
}
}
"EXIT" | "QUIT" => {
// Funnel through the OS close path so the unsaved-changes
// dialog runs before `iced::exit()`. Falls back to a hard
+2
View File
@@ -344,6 +344,8 @@ inventory::submit!(crate::command::CommandRegistration {
"XOPEN",
"REGION",
"REG",
"ARCHIVE",
"ETRANSMIT",
// Slice/section + interference + press-pull/thicken + 3D transforms + wall/pyramid.
"SLICE",
"SL",