diff --git a/+labkit/+ui/+app/private/buildFilePanelControl.m b/+labkit/+ui/+app/private/buildFilePanelControl.m index 6dd7345d..846b1fb2 100644 --- a/+labkit/+ui/+app/private/buildFilePanelControl.m +++ b/+labkit/+ui/+app/private/buildFilePanelControl.m @@ -455,7 +455,7 @@ for k = 1:numel(files) pathValue = ""; if isfield(files(k), 'path') - pathValue = string(files(k).path); + pathValue = filePanelScalarText(files(k).path, ""); end files(k).path = pathValue; [~, base, ext] = fileparts(char(pathValue)); @@ -464,11 +464,19 @@ name = pathValue; end files(k).name = name; - if ~isfield(files(k), 'displayName') || strlength(string(files(k).displayName)) == 0 + displayName = ""; + if isfield(files(k), 'displayName') + displayName = filePanelScalarText(files(k).displayName, ""); + end + if strlength(displayName) == 0 files(k).displayName = name; + else + files(k).displayName = displayName; end if ~isfield(files(k), 'status') files(k).status = ""; + else + files(k).status = filePanelScalarText(files(k).status, ""); end end end @@ -478,7 +486,7 @@ for k = 1:numel(files) id = ""; if isfield(files(k), 'id') - id = string(files(k).id); + id = filePanelScalarText(files(k).id, ""); end usedIds = seen(1:k-1); if strlength(id) == 0 || any(usedIds == id) diff --git a/+labkit/+ui/+app/private/filePanelScalarText.m b/+labkit/+ui/+app/private/filePanelScalarText.m new file mode 100644 index 00000000..338949cc --- /dev/null +++ b/+labkit/+ui/+app/private/filePanelScalarText.m @@ -0,0 +1,11 @@ +% Private filePanel helper. Expected caller: buildFilePanelControl. Inputs +% are file-entry text values that may be empty, scalar, or non-scalar. Output +% is a scalar string fallback or the first supplied text value. +function value = filePanelScalarText(rawValue, fallback) + value = string(rawValue); + if isempty(value) + value = string(fallback); + return; + end + value = value(1); +end diff --git a/+labkit/+ui/version.m b/+labkit/+ui/version.m index 69e5a316..92792c39 100644 --- a/+labkit/+ui/version.m +++ b/+labkit/+ui/version.m @@ -12,6 +12,6 @@ % compatible contract ranges implemented by this code, contract status, % and a short maintainer note. - info = labkit.contract.versionInfo("ui", "3.2.0", ">=3.0 <4", ... + info = labkit.contract.versionInfo("ui", "3.2.2", ">=3.0 <4", ... "stable", "UI 3.x app/spec/view/tool/diag contract with filePanel title context, debug trace, close guard, crash reports, and default text fitting."); end diff --git a/tests/cases/gui/labkit/ui/GuiLayoutUiDeclarativeAppTest.m b/tests/cases/gui/labkit/ui/GuiLayoutUiDeclarativeAppTest.m index 8c615a9c..7f835d05 100644 --- a/tests/cases/gui/labkit/ui/GuiLayoutUiDeclarativeAppTest.m +++ b/tests/cases/gui/labkit/ui/GuiLayoutUiDeclarativeAppTest.m @@ -299,6 +299,20 @@ function verify_gui_layout_ui_declarative_app() selection = labkit.ui.view.filePaths(labkit.ui.view.getValue(ui, 'sourceImages')); assert(isequal(selection, "b.png"), ... 'File helpers should apply semantic filePanel selection.'); + malformedFiles = struct('id', "", 'path', "", 'status', ""); + malformedFiles(1).id = strings(0, 1); + malformedFiles(1).path = string(fullfile(tempdir, 'folder_scan_a.png')); + malformedFiles(1).status = "needs center"; + malformedFiles(2).id = ["file1", "extra"]; + malformedFiles(2).path = string(fullfile(tempdir, 'folder_scan_b.png')); + malformedFiles(2).status = ["ready", "ignored"]; + labkit.ui.view.setValue(ui, 'sourceImages', malformedFiles); + normalizedFiles = labkit.ui.view.getFiles(ui, 'sourceImages'); + normalizedIds = string({normalizedFiles.id}).'; + normalizedStatus = string({normalizedFiles.status}).'; + assert(isequal(normalizedIds, ["file1"; "file2"]) && ... + isequal(normalizedStatus, ["needs center"; "ready"]), ... + 'filePanel setValue should scalarize malformed entry ids/status and regenerate duplicates.'); labkit.ui.view.appendLog(ui, 'logPanel', 'Completed.'); assert(any(contains(string(ui.controls.logPanel.textArea.Value), 'Completed.')), ... 'appendLog should append to the requested log panel.');