Refactor SelectFileDialog and SettingsTab for improved metadata handling and UI consistency

- Removed unused local_settings reference from qmldir.
- Enhanced SelectFileDialog to include a masterTypeFieldText property for better metadata representation.
- Updated normalizedRows to merge settingsModel.masters with sidecar data for dynamic UI updates.
- Adjusted column headers and removed the save button from the table model for a cleaner interface.
- Modified SettingsTab to streamline CSV file handling and ensure settings are saved upon updates.
This commit is contained in:
Jack.Le
2026-05-05 09:59:18 -07:00
parent b338eedb13
commit bbe7baea5b
3 changed files with 86 additions and 94 deletions
+62 -73
View File
@@ -23,6 +23,12 @@ Dialog {
property var tableModel: [] property var tableModel: []
property int selectedRow: -1 property int selectedRow: -1
property int metadataEditRow: -1 property int metadataEditRow: -1
readonly property string masterTypeFieldText: {
if (metadataEditRow < 0) return "";
const rec = tableModel[metadataEditRow];
if (!rec) return "";
return rec.masterType ?? "";
}
function openMetadataEditor(row) { function openMetadataEditor(row) {
metadataEditRow = row; metadataEditRow = row;
@@ -34,8 +40,9 @@ Dialog {
waferField.text = rec.wafer ?? ""; waferField.text = rec.wafer ?? "";
dateField.text = rec.date ?? ""; dateField.text = rec.date ?? "";
chamberField.text = rec.chamber ?? ""; chamberField.text = rec.chamber ?? "";
if (!chamberField.text && settingsModel.chamberId)
chamberField.text = settingsModel.chamberId;
notesField.text = rec.notes ?? ""; notesField.text = rec.notes ?? "";
selectedField.checked = rec.selected ?? false;
filePathLabel.text = rec.fileName ?? ""; filePathLabel.text = rec.fileName ?? "";
metadataEditDialog.open(); metadataEditDialog.open();
} }
@@ -48,26 +55,43 @@ Dialog {
metadataEditDialog.close(); metadataEditDialog.close();
return; return;
} }
file_browser.saveMetadata(rec.fileName ?? "", waferField.text, dateField.text, chamberField.text, notesField.text, selectedField.checked); file_browser.saveMetadata(rec.fileName ?? "", waferField.text, dateField.text, chamberField.text, notesField.text, false, "");
metadataEditDialog.close(); metadataEditDialog.close();
metadataEditRow = -1; metadataEditRow = -1;
} }
readonly property var headerTitles: ["", "Wafer", "Date", "Chamber", "Notes", "File", "Edit", "Save"] readonly property var headerTitles: ["Master", "Wafer", "Date", "Chamber", "Notes", "File", "Edit"]
readonly property var normalizedRows: (tableModel || []).map(function (row) { // Build a path→family reverse map from settingsModel.masters.
// settingsModel is a QML context property; accessing it here makes the
// binding reactive — any mastersChanged signal re-evaluates normalizedRows.
function masterFamilyForPath(filePath) {
const m = settingsModel.masters;
for (var fam in m) {
if (m[fam] && m[fam] === filePath)
return fam;
}
return "";
}
readonly property var normalizedRows: {
// Touch settingsModel.masters so QML tracks this dependency.
const _ = settingsModel.masters;
return (tableModel || []).map(function(row) {
row = row || {}; row = row || {};
// settingsModel is the authoritative source; fall back to sidecar masterType.
const masterType = root.masterFamilyForPath(row.fileName ?? "") || row.masterType || "";
return { return {
select: row.selected ?? false, masterType: masterType,
wafer: row.wafer ?? "", wafer: row.wafer ?? "",
date: row.date ?? "", date: row.date ?? "",
chamber: row.chamber ?? "", chamber: row.chamber ?? "",
edit: "", edit: "",
save: "",
notes: row.notes ?? "", notes: row.notes ?? "",
fileName: row.fileName ?? "", fileName: row.fileName ?? "",
highlight: row.highlight ?? false highlight: row.highlight ?? false
}; };
}) });
}
// ===== Reusable Controls ===== // ===== Reusable Controls =====
component DialogActionButton: Button { component DialogActionButton: Button {
@@ -234,27 +258,26 @@ Dialog {
flickableDirection: Flickable.VerticalFlick flickableDirection: Flickable.VerticalFlick
columnWidthProvider: function (col) { columnWidthProvider: function (col) {
// [select, wafer, date, chamber, notes, file (variable), edit, save] // [master, wafer, date, chamber, notes, file (variable), edit]
const fixed = { const fixed = {
0: 40, 0: 48,
1: 90, 1: 90,
2: 170, 2: 170,
3: 120, 3: 120,
4: 180, 4: 180,
6: 56, 6: 56
7: 56
}; };
if (fixed.hasOwnProperty(col)) if (col in fixed)
return fixed[col]; return fixed[col];
// col 5 (File) takes remaining width // col 5 (File) takes remaining width
const w = Math.max(400, tableView.width); const w = Math.max(400, tableView.width);
const used = 40 + 90 + 170 + 120 + 180 + 56 + 56; const used = 48 + 90 + 170 + 120 + 180 + 56;
return Math.max(120, w - used); return Math.max(120, w - used);
} }
model: TableModel { model: TableModel {
TableModelColumn { TableModelColumn {
display: "select" display: "masterType"
} }
TableModelColumn { TableModelColumn {
display: "wafer" display: "wafer"
@@ -274,9 +297,6 @@ Dialog {
TableModelColumn { TableModelColumn {
display: "edit" display: "edit"
} }
TableModelColumn {
display: "save"
}
rows: root.normalizedRows rows: root.normalizedRows
} }
@@ -296,16 +316,24 @@ Dialog {
return row % 2 === 0 ? Theme.cardBackground : Theme.tone100; return row % 2 === 0 ? Theme.cardBackground : Theme.tone100;
} }
// Checkbox (col 0) // Master type indicator (col 0)
// Reads normalizedRows (which merges settingsModel.masters + sidecar).
Loader { Loader {
anchors.fill: parent anchors.fill: parent
active: column === 0 active: column === 0
sourceComponent: CheckBox { sourceComponent: Text {
anchors.centerIn: parent anchors.fill: parent
checked: root.tableModel[row]?.selected ?? false horizontalAlignment: Text.AlignHCenter
onCheckedChanged: { verticalAlignment: Text.AlignVCenter
if (root.tableModel[row]) text: {
root.tableModel[row].selected = checked; const mt = root.normalizedRows[row]?.masterType ?? "";
return mt || "—";
}
font.pixelSize: 14
font.bold: true
color: {
const mt = root.normalizedRows[row]?.masterType ?? "";
return mt ? Theme.primaryAccent : Theme.fieldPlaceholder;
} }
} }
} }
@@ -338,39 +366,6 @@ Dialog {
} }
} }
// Save button (col 7)
Loader {
anchors.fill: parent
anchors.margins: 4
active: column === 7
sourceComponent: Button {
hoverEnabled: true
text: "Save"
font.pixelSize: 12
onClicked: {
const record = root.tableModel[row];
if (!record)
return;
file_browser.saveMetadata(record.fileName ?? "", record.wafer ?? "", record.date ?? "", record.chamber ?? "", record.notes ?? "", record.selected ?? false);
}
background: Rectangle {
radius: Theme.radiusXs
color: parent.down ? Theme.buttonNeutralPressed : parent.hovered ? Theme.buttonNeutralHover : Theme.buttonNeutralBackground
border.width: Theme.borderThin
border.color: Theme.fieldBorder
}
contentItem: Text {
text: parent.text
color: Theme.buttonNeutralText
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 12
}
}
}
// Text columns: Wafer (1), Date (2), File (5) // Text columns: Wafer (1), Date (2), File (5)
Loader { Loader {
anchors.fill: parent anchors.fill: parent
@@ -386,8 +381,10 @@ Dialog {
return record.wafer ?? ""; return record.wafer ?? "";
if (column === 2) if (column === 2)
return record.date ?? ""; return record.date ?? "";
if (column === 5) if (column === 5) {
return record.fileName ?? ""; const p = record.fileName ?? "";
return p.split("/").pop();
}
return ""; return "";
} }
elide: Text.ElideRight elide: Text.ElideRight
@@ -419,7 +416,7 @@ Dialog {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
enabled: column !== 0 && column !== 6 && column !== 7 enabled: column !== 6
onClicked: { onClicked: {
root.selectedRow = row; root.selectedRow = row;
root.selectedPath = root.tableModel[row]?.fileName ?? ""; root.selectedPath = root.tableModel[row]?.fileName ?? "";
@@ -442,12 +439,6 @@ Dialog {
} }
} }
DialogActionButton {
text: "Cancel"
Layout.preferredWidth: 90
onClicked: root.close()
}
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 32 Layout.preferredHeight: 32
@@ -477,7 +468,7 @@ Dialog {
id: metadataEditDialog id: metadataEditDialog
parent: Overlay.overlay parent: Overlay.overlay
modal: true modal: true
title: qsTr("Edit File Information") title: qsTr("Edit Metadata")
width: 520 width: 520
height: 520 height: 520
padding: 16 padding: 16
@@ -527,12 +518,14 @@ Dialog {
text: qsTr("File") text: qsTr("File")
font.bold: true font.bold: true
color: Theme.headingColor color: Theme.headingColor
Layout.topMargin: 8
} }
Text { Text {
id: filePathLabel id: filePathLabel
Layout.fillWidth: true Layout.fillWidth: true
Layout.maximumHeight: 56 Layout.maximumHeight: 56
Layout.bottomMargin: 16
wrapMode: Text.WrapAnywhere wrapMode: Text.WrapAnywhere
maximumLineCount: 3 maximumLineCount: 3
elide: Text.ElideRight elide: Text.ElideRight
@@ -580,14 +573,10 @@ Dialog {
Layout.preferredHeight: 36 Layout.preferredHeight: 36
} }
CheckBox {
id: selectedField
text: qsTr("Selected for processing")
}
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 8 Layout.topMargin: 16
Layout.bottomMargin: 16
spacing: 8 spacing: 8
Item { Item {
+12 -6
View File
@@ -23,8 +23,7 @@ Item {
} }
function handleCsvSelected(filePath) { function handleCsvSelected(filePath) {
console.log("Doing work with:", filePath); // Selection confirmed — metadata editing is handled inline inside SelectFileDialog.
// @todo: implement CSV metadata handling after file selection.
} }
// ===== Settings Data Helpers ===== // ===== Settings Data Helpers =====
@@ -136,7 +135,7 @@ Item {
title: "Choose Master CSV" title: "Choose Master CSV"
nameFilters: ["CSV files (*.csv)"] nameFilters: ["CSV files (*.csv)"]
property string targetFamily: "" property string targetFamily: ""
onAccepted: settingsModel.setMaster(targetFamily, selectedFile.toLocalFile()) onAccepted: settingsModel.setMaster(targetFamily, String(selectedFile).replace(/^file:\/\//, ""))
} }
// ===== Settings Page Layout ===== // ===== Settings Page Layout =====
@@ -206,7 +205,6 @@ Item {
Layout.minimumWidth: Theme.settingsFieldMinWidth Layout.minimumWidth: Theme.settingsFieldMinWidth
placeholderText: "Enter chamber ID" placeholderText: "Enter chamber ID"
text: settingsModel.chamberId text: settingsModel.chamberId
onEditingFinished: settingsModel.setChamberId(text)
Connections { Connections {
target: settingsModel target: settingsModel
@@ -222,7 +220,10 @@ Item {
text: "Set" text: "Set"
Layout.preferredWidth: 90 Layout.preferredWidth: 90
Layout.preferredHeight: Theme.settingsButtonHeight Layout.preferredHeight: Theme.settingsButtonHeight
onClicked: settingsModel.setChamberId(chamberField.text) onClicked: {
settingsModel.setChamberId(chamberField.text);
settingsModel.saveSettings();
}
} }
} }
} }
@@ -389,6 +390,11 @@ Item {
Layout.fillWidth: true Layout.fillWidth: true
} }
} }
// Bottom spacer so last group isn't flush with scroll edge
Item {
Layout.preferredHeight: Theme.settingsSectionSpacing
}
} }
} }
@@ -406,7 +412,7 @@ Item {
} }
GradientStop { GradientStop {
position: 1.0 position: 1.0
color: Qt.transparent color: Qt.rgba(0, 0, 0, 0)
} }
} }
-3
View File
@@ -3,6 +3,3 @@ module ISC.Tabs
# ===== Tab Components ===== # ===== Tab Components =====
SettingsTab 1.0 SettingsTab.qml SettingsTab 1.0 SettingsTab.qml
# ===== Local Python Helpers =====
local_settings 1.0 local_settings.py