feat: add interactive folder selection for CSV saves and stabilize cross-platform dependency locking
This commit is contained in:
@@ -24,8 +24,15 @@ Rectangle {
|
||||
property int selectedTabIndex: 0
|
||||
property int selectedSideActionIndex: -1 // nothing active on startup
|
||||
|
||||
property bool memoryRead: false
|
||||
property bool waferDetected: false
|
||||
|
||||
Connections {
|
||||
target: deviceController
|
||||
function onDetectResult(result){
|
||||
//result is a waferInfo dict on success, None on failure
|
||||
root.waferDetected = (result != null && result!= undefined)
|
||||
}
|
||||
function onParsedDataReady(result) {
|
||||
if (result.success && result.csv_path) {
|
||||
// Load the freshly read CSV into the player
|
||||
@@ -36,8 +43,23 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
target: deviceController
|
||||
function onReadResult(result) {
|
||||
// result has "success" key on success, "error" key on failure
|
||||
root.memoryRead = (result !== null &&
|
||||
result !== undefined &&
|
||||
result.success === true)
|
||||
|
||||
// ===== Main Two-Column Layout =====
|
||||
if (root.memoryRead) {
|
||||
console.log(`[P1.1] Memory read complete: ${result.bytes} bytes`)
|
||||
} else {
|
||||
console.log(`[P1.1] Read failed: ${result.error || "unknown"}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Main Two-Column Layout ======
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
@@ -66,6 +88,16 @@ Rectangle {
|
||||
Button {
|
||||
id: control
|
||||
text: modelData
|
||||
enabled: {
|
||||
switch (index) {
|
||||
case 0: return true // DETECT WAFER
|
||||
case 1: return root.waferDetected // READ MEMORY
|
||||
case 2: return root.memoryRead // OPEN CSV IN EXCEL
|
||||
case 3: return root.waferDetected // ERASE MEMORY
|
||||
case 4: return root.memoryRead // IMPORT DATA
|
||||
default: return true // STORED DATA
|
||||
}
|
||||
}
|
||||
property bool isActive: index === root.selectedSideActionIndex
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Math.max(Theme.sideButtonMinHeight, sideRail.computedButtonHeight)
|
||||
@@ -74,6 +106,7 @@ Rectangle {
|
||||
root.selectedSideActionIndex = index
|
||||
root.selectedTabIndex = 0 // always jump to Status tab
|
||||
if (index === 0) {
|
||||
root.memoryRead = false
|
||||
streamController.setMode("review")
|
||||
streamController.stopStream()
|
||||
deviceController.detectWafer()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Dialogs
|
||||
import ISC
|
||||
|
||||
// ===== Status Tab =====
|
||||
@@ -29,6 +30,28 @@ ColumnLayout {
|
||||
property string csvPath: ""
|
||||
property bool dataParsed: false
|
||||
|
||||
function cleanFolderUrl(url) {
|
||||
return decodeURIComponent(String(url).replace(/^file:\/\//, ""))
|
||||
}
|
||||
|
||||
function currentFamilyCode() {
|
||||
var info = deviceController.lastWaferInfo
|
||||
return info && info.length > 0 ? (info[0] || "") : ""
|
||||
}
|
||||
|
||||
function parseAndSavePendingRead() {
|
||||
deviceController.parseAndSaveData(root.currentFamilyCode(), deviceController.selectedPort || "")
|
||||
}
|
||||
|
||||
FolderDialog {
|
||||
id: saveDirDialog
|
||||
title: "Choose CSV Save Folder"
|
||||
onAccepted: {
|
||||
deviceController.setSaveDataDir(root.cleanFolderUrl(selectedFolder))
|
||||
root.parseAndSavePendingRead()
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Empty state — nothing shown until detect fires =====
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
@@ -345,6 +368,9 @@ ColumnLayout {
|
||||
root.dataRows = 0
|
||||
root.dataCols = 0
|
||||
root.csvPath = ""
|
||||
|
||||
if (result && result.success === true)
|
||||
saveDirDialog.open()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -303,7 +303,8 @@ class DeviceController(QObject):
|
||||
"""Read wafer memory in a background thread.
|
||||
|
||||
Uses the family code and port from the last detect.
|
||||
Emits readResult on completion, then auto-chains to parseAndSaveData.
|
||||
Emits readResult on completion; QML prompts for the save directory
|
||||
before calling parseAndSaveData.
|
||||
"""
|
||||
if self._operation_in_progress:
|
||||
self._append_log("Already busy — ignoring read request")
|
||||
@@ -350,9 +351,7 @@ class DeviceController(QObject):
|
||||
self._raw_bytes = data
|
||||
self.readResult.emit({"success": True, "bytes": len(data)})
|
||||
self._set_operation_progress(False)
|
||||
# Auto-chain: read → parse → save (matches C# behavior).
|
||||
# Parse runs on main thread — it's CPU-bound but bounded (~1s).
|
||||
self.parseAndSaveData(family_code, port)
|
||||
self._append_log("Memory read complete - choose save directory to save CSV")
|
||||
self._save_status()
|
||||
return
|
||||
self._connection_status = "Disconnected"
|
||||
@@ -489,6 +488,7 @@ class DeviceController(QObject):
|
||||
return
|
||||
|
||||
self._append_log(f"Saved CSV: {csv_path}")
|
||||
self._last_csv_path = csv_path
|
||||
|
||||
# Load data into the QAbstractTableModel
|
||||
self._data_model.load_data(temp_data, cols)
|
||||
|
||||
Reference in New Issue
Block a user