fix(sheetset): wasm build, lock files and sheet set field refresh

- `.dst` read/write go through native-only helpers (a browser answers
  "Not available"); the folder pickers are web no-ops; time stamps use
  iced::time (web-safe).
- Lock files are written only for drawings that are sheets of an open set,
  released when the last set closes, and a lock a crashed session left
  (recorded with its process id, same user and machine) is taken back.
  The `.dwl2` header is well-formed and the date line comes from the OS
  long date on every platform. The 1 Hz poll runs only while a set is open.
- Refreshing sheet set fields never stores `####`: fields no open set
  resolves keep their value, and only the hosts that changed are redrawn
  (and their tab marked modified).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 5.5 committed 2026-10-06 09:29:14 +03:00
1 parent 078306d8fc
commit 76f4bb97dc
5 files changed
+219 -71

No files matched your search

+61 -2
View File
@@ -387,10 +387,69 @@ pub fn attach_attribute_fields(document: &mut CadDocument, insert: Handle) -> Ve
document.attach_attribute_fields(insert, &context)
}
/// Store fresh values for the sheet set fields (after a sheet set changed).
/// Store fresh values for the sheet set fields (after a sheet set changed)
/// and return the hosts whose text changed. A field no open sheet set
/// resolves (`####`: its set was closed or not found) keeps its stored value.
pub fn refresh_sheet_set_fields(document: &mut CadDocument) -> Vec<Handle> {
let context = OcsFieldContext(None);
document.refresh_sheet_set_fields(&context)
let unresolved: Vec<(Handle, String)> = document
.fields
.values()
.filter(|f| f.evaluator.starts_with("AcSm"))
.filter(|f| {
let host = field_host(document, f.handle).unwrap_or(Handle::NULL);
codec::fields::resolve_handle(document, f.handle, host, &context).is_none_or(|v| v == "####")
})
.map(|f| (f.handle, f.evaluator.clone()))
.collect();
// ponytail: the engine refreshes every sheet set field, so the unresolved
// ones are hidden from it (evaluator cleared) for this one call; a
// "skip unresolved" switch in the engine would replace this.
for (h, _) in &unresolved {
if let Some(f) = document.fields.get_mut(h) {
f.evaluator.clear();
}
}
let changed = document.refresh_sheet_set_fields(&context);
for (h, evaluator) in unresolved {
if let Some(f) = document.fields.get_mut(&h) {
f.evaluator = evaluator;
}
}
changed
}
/// The entity hosting field `field`: up its owner chain (fields, then the
/// field dictionary and extension dictionary) to the first non-object.
fn field_host(document: &CadDocument, field: Handle) -> Option<Handle> {
let owner = |h: Handle| -> Option<Handle> {
if let Some(f) = document.fields.get(&h) {
return Some(f.owner);
}
match document.objects.get(&h)? {
codec::objects::ObjectType::Dictionary(d) => Some(d.owner),
codec::objects::ObjectType::Unknown { owner, .. } => Some(*owner),
_ => None,
}
};
let mut h = field;
for _ in 0..12 {
let o = owner(h)?;
if owner(o).is_none() {
return Some(o);
}
h = o;
}
None
}
/// Now as the OS long date, two spaces and the 24-hour time
/// (`Monday, October 5, 2026 09:26:39`).
pub fn long_date_time_now() -> String {
let locale = os_date_locale();
let picture = format!("{} HH:mm:ss", locale.long_date);
let now = now_utc_julian() + utc_offset_days();
codec::fields::format_dt_in(codec::fields::julian_parts(now), &picture, &locale)
}
/// [`attach_attribute_fields`] with every field code passed through `map`.