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:
@@ -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 ?? "";
|
||||||
notesField.text = rec.notes ?? "";
|
if (!chamberField.text && settingsModel.chamberId)
|
||||||
selectedField.checked = rec.selected ?? false;
|
chamberField.text = settingsModel.chamberId;
|
||||||
|
notesField.text = rec.notes ?? "";
|
||||||
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.
|
||||||
row = row || {};
|
// settingsModel is a QML context property; accessing it here makes the
|
||||||
return {
|
// binding reactive — any mastersChanged signal re-evaluates normalizedRows.
|
||||||
select: row.selected ?? false,
|
function masterFamilyForPath(filePath) {
|
||||||
wafer: row.wafer ?? "",
|
const m = settingsModel.masters;
|
||||||
date: row.date ?? "",
|
for (var fam in m) {
|
||||||
chamber: row.chamber ?? "",
|
if (m[fam] && m[fam] === filePath)
|
||||||
edit: "",
|
return fam;
|
||||||
save: "",
|
}
|
||||||
notes: row.notes ?? "",
|
return "";
|
||||||
fileName: row.fileName ?? "",
|
}
|
||||||
highlight: row.highlight ?? false
|
|
||||||
};
|
readonly property var normalizedRows: {
|
||||||
})
|
// Touch settingsModel.masters so QML tracks this dependency.
|
||||||
|
const _ = settingsModel.masters;
|
||||||
|
return (tableModel || []).map(function(row) {
|
||||||
|
row = row || {};
|
||||||
|
// settingsModel is the authoritative source; fall back to sidecar masterType.
|
||||||
|
const masterType = root.masterFamilyForPath(row.fileName ?? "") || row.masterType || "";
|
||||||
|
return {
|
||||||
|
masterType: masterType,
|
||||||
|
wafer: row.wafer ?? "",
|
||||||
|
date: row.date ?? "",
|
||||||
|
chamber: row.chamber ?? "",
|
||||||
|
edit: "",
|
||||||
|
notes: row.notes ?? "",
|
||||||
|
fileName: row.fileName ?? "",
|
||||||
|
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
|
||||||
@@ -417,9 +414,9 @@ 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 {
|
||||||
|
|||||||
@@ -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,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
|
|
||||||
|
|||||||
Reference in New Issue
Block a user