feat(xref): reference list with stale and orphaned status detection

Reference list rows showing stale and orphaned states with handle-based identity.
This commit is contained in:
Karim Jerbi committed 2026-09-15 23:56:31 +01:00
1 parent 37e2b50e1c
commit 42219a4b8c
9 files changed
+442 -1141

No files matched your search

+7 -2
View File
@@ -578,8 +578,13 @@ impl OpenCADStudio {
}
}
cmd if cmd.eq_ignore_ascii_case("XREF") || cmd.to_ascii_uppercase().starts_with("XREF ") => {
// XREF sub-option dispatcher (Task 5). The verb is
// XREFMAN — open/focus the Reference Manager palette (display-only,
// Task 7). The XREF command below is untouched.
"XREFMAN" => {
return Some(Task::done(Message::ToggleXrefManager));
}
cmd if cmd.eq_ignore_ascii_case("XREF") || cmd.to_ascii_uppercase().starts_with("XREF ") => { // XREF sub-option dispatcher (Task 5). The verb is
// case-insensitive; arguments split on whitespace.
let rest = cmd
.splitn(2, char::is_whitespace)
+1
View File
@@ -713,6 +713,7 @@ inventory::submit!(crate::command::CommandRegistration {
"XDATA",
"XR",
"XREF",
"XREFMAN",
"XRELOAD",
"ZOOM",
"ZS",
+14
View File
@@ -708,6 +708,8 @@ pub(super) struct OpenCADStudio {
pub(crate) dock_drag_target: Option<(crate::app::config::DockSide, usize)>,
/// Docked Insert Block panel state (search, preview size, cached thumbnails).
pub(crate) block_palette: crate::ui::window::block_palette::BlockPalette,
/// Reference Manager palette state (display-only in Task 7).
pub(crate) xref_manager: crate::ui::window::xref_manager::XrefManagerPanel,
/// Whether the document file tabs are shown at the top (FILETAB).
show_file_tabs: bool,
/// Whether the layout/paper-space tabs are shown at the bottom (LAYOUTTAB).
@@ -1728,6 +1730,7 @@ pub enum ModalKind {
UpdateNotice,
DonationPrompt,
Layers,
XrefManager,
LayerStateManager,
LayerTranslator,
DrawingUnits,
@@ -2344,6 +2347,16 @@ pub enum Message {
/// active command as if typed (empty keyword = Enter). (#304)
CommandOptionPick(String),
ToggleLayers,
/// Open/focus (or close) the Reference Manager palette.
ToggleXrefManager,
/// Rescan the active drawing's references into the palette.
XrefManagerRefresh,
/// Toggle one palette row (entry index) in the multi-selection set.
XrefManagerSelect(usize),
/// Flip the palette's list/tree presentation.
XrefManagerToggleTree,
/// Expand/collapse one tree parent (block-record handle key).
XrefManagerToggleExpand(u64),
LayerToggleVisible(usize),
LayerToggleLock(usize),
LayerToggleFreeze(usize),
@@ -3710,6 +3723,7 @@ impl OpenCADStudio {
show_properties: true,
show_block_palette: false,
block_palette: Default::default(),
xref_manager: Default::default(),
dock: Default::default(),
dock_expanded: None,
dock_dragging: None,
+26
View File
@@ -757,6 +757,32 @@ pub(super) fn on_ribbon_tool_click(&mut self, tool_id: String, event: ModuleEven
self.refresh_block_palette();
}
}
/// Rebuild the Reference Manager's entry list from the active drawing.
/// Display-only: `collect_entries` stats files but mutates nothing.
pub(crate) fn refresh_xref_manager(&mut self) {
let i = self.active_tab;
let base_dir: std::path::PathBuf = self.tabs[i]
.current_path
.as_ref()
.and_then(|p| p.parent().map(|p| p.to_path_buf()))
.unwrap_or_else(|| std::path::PathBuf::from("."));
let tab_id = self.tabs[i].id;
self.xref_manager
.refresh(&self.tabs[i].scene.document, &base_dir);
self.xref_manager.source_tab_id = Some(tab_id);
}
/// Re-scan when the palette is open but showing another tab's drawing.
pub(crate) fn refresh_xref_manager_if_stale(&mut self) {
if self.active_modal != Some(crate::app::ModalKind::XrefManager) {
return;
}
let i = self.active_tab;
if self.xref_manager.source_tab_id != Some(self.tabs[i].id) {
self.refresh_xref_manager();
}
}
}
#[cfg(test)]
+30
View File
@@ -314,6 +314,9 @@ impl OpenCADStudio {
// The block panel watches the drawing's block list and rebuilds its
// thumbnails whenever the names change (BLOCK define, file open, …).
self.refresh_block_palette_if_stale();
// The Reference Manager watches the active drawing and re-scans when
// the palette is open on another tab's entries.
self.refresh_xref_manager_if_stale();
// Let V4 plugins observe selection changes that happened while handling
// this message (picking, window select, QSELECT, SELECTALL, grip edits,
// and plugin request draining).
@@ -2127,6 +2130,33 @@ impl OpenCADStudio {
Task::none()
}
Message::ToggleXrefManager => {
if self.active_modal == Some(super::ModalKind::XrefManager) {
self.active_modal = None;
self.reset_modal_geometry();
} else {
self.refresh_xref_manager();
self.active_modal = Some(super::ModalKind::XrefManager);
}
Task::none()
}
Message::XrefManagerRefresh => {
self.refresh_xref_manager();
Task::none()
}
Message::XrefManagerSelect(index) => {
self.xref_manager.toggle_select(index);
Task::none()
}
Message::XrefManagerToggleTree => {
self.xref_manager.toggle_tree();
Task::none()
}
Message::XrefManagerToggleExpand(key) => {
self.xref_manager.toggle_expand(key);
Task::none()
}
Message::LayerStateManagerOpen => {
let i = self.active_tab;
self.ribbon.close_dropdown();
+7
View File
@@ -20,6 +20,8 @@ impl OpenCADStudio {
Some(K::UpdateNotice) => crate::tr!("modal", "update-available"),
Some(K::DonationPrompt) => crate::tr!("donation", "title"),
Some(K::Layers) => crate::tr!("modal", "layer-manager"),
// XREF-Task8: locale (hardcoded until Task 8 batches locale strings).
Some(K::XrefManager) => "Reference Manager".to_string(),
Some(K::LayerStateManager) => crate::tr!("modal", "layer-state-manager"),
Some(K::LayerTranslator) => crate::t!("Layer Translator").into_owned(),
Some(K::DrawingUnits) => crate::t!("Drawing Units").into_owned(),
@@ -394,6 +396,11 @@ impl OpenCADStudio {
|flow| tab.layers.view_window(self.layer_name_col_w, flow),
)
}
super::super::ModalKind::XrefManager => {
sized_flow(ex, 960, 520, |flow| {
self.xref_manager.view_window(flow)
})
}
super::super::ModalKind::LayerTranslator => {
use crate::modules::draw::layers::laytrans;
let i = self.active_tab;