Merge remote-tracking branch 'origin/main' into codex/pdf-attach-parity

# Conflicts:
#	locales/ar-SA/opencadstudio.ftl
#	locales/bg-BG/opencadstudio.ftl
#	locales/cs-CZ/opencadstudio.ftl
#	locales/de-DE/opencadstudio.ftl
#	locales/el-GR/opencadstudio.ftl
#	locales/en-US/opencadstudio.ftl
#	locales/es-ES/opencadstudio.ftl
#	locales/fi-FI/opencadstudio.ftl
#	locales/fr-FR/opencadstudio.ftl
#	locales/hi-IN/opencadstudio.ftl
#	locales/hu-HU/opencadstudio.ftl
#	locales/it-IT/opencadstudio.ftl
#	locales/ja-JP/opencadstudio.ftl
#	locales/ko-KR/opencadstudio.ftl
#	locales/nl-NL/opencadstudio.ftl
#	locales/pl-PL/opencadstudio.ftl
#	locales/pt-BR/opencadstudio.ftl
#	locales/ru-RU/opencadstudio.ftl
#	locales/tr-TR/opencadstudio.ftl
#	locales/zh-CN/opencadstudio.ftl
#	locales/zh-TW/opencadstudio.ftl
#	src/app/control/actions.rs
#	src/app/mod.rs
#	src/app/update/mod.rs
#	src/app/view/modal.rs
#	src/io/xref.rs
#	src/ui/window/mod.rs
This commit is contained in:
ramox81 committed 2026-09-24 19:38:48 +03:00
commit c1ecb0edaf
77 files changed
+5695 -606

No files matched your search

+9
View File
@@ -52,6 +52,7 @@ pub(super) const NAMES: &[&str] = &[
"pdf_page_select",
"ribbon_tab",
"ribbon_dropdown",
"dialog_ok",
"close_document",
"toggle_properties",
"toggle_layers",
@@ -705,6 +706,14 @@ impl OpenCADStudio {
_ => return Err(failure("no_dialog", "No PDF dialog is open")),
})
}
// The open dialog's OK button.
"dialog_ok" => match self.active_modal {
Some(crate::app::ModalKind::XrefAttach) => Message::XrefAttach(
crate::ui::window::xref_attach::XrefAttachMsg::Apply,
),
Some(crate::app::ModalKind::BlockDefinition) => Message::BlockDefApply,
_ => return Err(failure("no_dialog", "No dialog with an OK button is open")),
},
"close_document" => Message::TabClose(self.active_tab),
"toggle_properties" => Message::ToggleProperties,
"toggle_layers" => Message::ToggleLayers,
+40 -3
View File
@@ -426,8 +426,10 @@ impl OpenCADStudio {
pub(super) fn control_state(&self) -> Value {
let tab = &self.tabs[self.active_tab];
let command = tab.active_cmd.as_deref().map(active_command_metadata);
let missing_fonts = crate::io::font_repo::missing_shx_fonts(&tab.scene.document);
json!({"ok":true,"protocol":1,"session_id":session_id(),"version":env!("OCS_APP_VERSION"),
"mode":if self.main_window.is_some(){"gui"}else{"headless"},"enabled":self.control.enabled,
"read_only":self.read_only,"missing_fonts":missing_fonts,
"document_id":tab.id,"revision":tab.edit_revision,"geometry_revision":tab.scene.geometry_epoch,"camera_revision":tab.scene.camera_generation,
"hand_seed":format!("{:X}",tab.scene.document.header.handle_seed.max(tab.scene.document.next_handle())),
"plugins":plugin_ids(),
@@ -442,7 +444,7 @@ impl OpenCADStudio {
"mtext_editor":self.mtext_editor.as_ref().map(|e|json!({"text":e.content.text(),"height":e.height,"style":e.style})),
"text_editor":self.text_inline.is_some(),"event_cursor":self.control.serial,
"operation":self.control.pending.as_ref().map(|p| &p.id),
"capabilities":["commands","command_manifest","step_input","batch","compact_results","entity_pick","structure_pick","selection","user_select","properties","records","record_schemas","record_filters","atomic_record_updates","layers","history","documents","events","capture","viewport_capture","measure","spatial_query"]
"capabilities":["commands","command_manifest","step_input","batch","compact_results","entity_pick","structure_pick","selection","user_select","properties","records","record_schemas","record_filters","atomic_record_updates","layers","history","documents","events","capture","viewport_capture","measure","spatial_query","audit","verified_save","explicit_save_version"]
})
}
@@ -467,6 +469,7 @@ impl OpenCADStudio {
| "history"
| "xdata_get"
| "get_selection"
| "audit"
);
if !query && !self.control.enabled {
return (
@@ -972,8 +975,36 @@ impl OpenCADStudio {
.map(std::path::PathBuf::from)
.or_else(|| self.tabs[i].current_path.clone())
.ok_or_else(|| failure("path_required", "Supply a save path"))?;
let default_is_dxf = crate::io::source_is_dxf(
self.tabs[i].current_path.as_deref(),
&self.tabs[i].scene.document,
);
let (version, is_dxf) = super::automation::requested_save_target(
req,
self.tabs[i].scene.document.version,
default_is_dxf,
Some(&path),
)
.map_err(|error| failure("invalid_target", error))?;
let dropped = crate::io::dropped_on_save_count(
&self.tabs[i].scene.document,
version,
is_dxf,
);
if dropped > 0 && req["allow_lossy"].as_bool() != Some(true) {
return Err(failure(
"lossy_conversion_not_acknowledged",
format!(
"Conversion would drop {dropped} unsupported record(s); set allow_lossy=true to acknowledge"
),
));
}
self.set_control_result(json!({
"saved":path,"target_format":if is_dxf { "dxf" } else { "dwg" },
"target_version":format!("{version:?}"),"dropped_on_save":dropped,
}));
if self.main_window.is_none() {
self.save_tab_synchronously_protected(i, path, true)
self.save_tab_synchronously_protected_as(i, path, version, true)
.map_err(|e| failure("save_failed", e))?;
Task::none()
} else {
@@ -981,7 +1012,7 @@ impl OpenCADStudio {
self.queue_native_save(
i,
path,
acadrust::DxfVersion::AC1032,
version,
super::SavePurpose::SaveAs,
super::SaveContinuation::None,
true,
@@ -989,6 +1020,12 @@ impl OpenCADStudio {
)
}
}
#[cfg(not(target_arch = "wasm32"))]
"save_verified" => {
let result = self.save_verified_request(req)?;
self.set_control_result(result);
Task::none()
}
"capture" => {
let window = self
.main_window