Work in progress
This commit is contained in:
268
readdisk.py
268
readdisk.py
@ -1,6 +1,6 @@
|
||||
import sys, os, subprocess
|
||||
from PySide6.QtWidgets import QApplication, QDialog, QButtonGroup, QFileDialog, QMessageBox
|
||||
from PySide6.QtCore import Slot
|
||||
from PySide6.QtCore import QCoreApplication, Slot
|
||||
from PySide6.QtGui import QIntValidator
|
||||
# Import the generated UI class from the ui_form.py file
|
||||
from ui_read_disk import Ui_ReadDialog
|
||||
@ -16,13 +16,11 @@ class ReadDiskWindow(QDialog):
|
||||
self.flippy_type_group = QButtonGroup(self)
|
||||
self.flippy_type_group.addButton(self.ui.rb_panasonic, 1)
|
||||
self.flippy_type_group.addButton(self.ui.rb_teac, 2)
|
||||
|
||||
self.pin2_setting_group = QButtonGroup(self)
|
||||
self.pin2_setting_group.addButton(self.ui.rb_pin2_high, 1)
|
||||
self.pin2_setting_group.addButton(self.ui.rb_pin2_low, 2)
|
||||
|
||||
# --- Connect Signals to Slots ---
|
||||
self.ui.cb_fake_index.toggled.connect(self.on_update_settings)
|
||||
self.ui.cb_bitrate.toggled.connect(self.on_update_settings)
|
||||
self.ui.cb_double_step.toggled.connect(self.on_update_settings)
|
||||
self.ui.cb_revs.toggled.connect(self.on_update_settings)
|
||||
@ -62,50 +60,47 @@ class ReadDiskWindow(QDialog):
|
||||
self.ui.le_adjust_speed.textChanged.connect(self.on_update_settings)
|
||||
self.ui.le_suffix.textChanged.connect(self.on_update_settings)
|
||||
self.ui.le_fileprefix.textChanged.connect(self.on_update_settings)
|
||||
#self.ui.btn_suffix_inc.clicked.connect(self.on_update_settings)
|
||||
#self.ui.btn_suffix_dec.clicked.connect(self.on_update_settings)
|
||||
# self.ui.btn_path_select.clicked.connect(self.on_path_select)
|
||||
self.ui.btn_file_select.clicked.connect(self.on_update_settings)
|
||||
self.ui.btn_file_select.clicked.connect(self.on_btn_file_select_clicked)
|
||||
self.ui.cb_format.toggled.connect(self.on_update_settings)
|
||||
self.ui.cb_inc.toggled.connect(self.on_update_settings)
|
||||
|
||||
# --- Connect Buttons to Dialog's Built-in Slots ---
|
||||
# The "Launch" button will "accept" the dialog (like OK)
|
||||
# The "Back" button will "reject" the dialog (like Cancel)
|
||||
self.ui.btn_launch.clicked.connect(self.on_launch)
|
||||
self.ui.btn_back.clicked.connect(self.reject)
|
||||
self.ui.btn_path_select.clicked.connect(self.on_btn_path_select_clicked)
|
||||
|
||||
# Initialize command attribute
|
||||
self.command = ""
|
||||
self.device = ""
|
||||
|
||||
@Slot()
|
||||
def on_btn_abort_clicked(self) -> None:
|
||||
self.abort = True
|
||||
self.ui.btn_abort.setEnabled(False)
|
||||
|
||||
|
||||
def calc_suffix(self, inc: int) -> None:
|
||||
# Increments or decrements the numeric value in the suffix text field.
|
||||
"""Increment or decrement the numeric value in the suffix text field."""
|
||||
try:
|
||||
current_value = int(self.ui.le_suffix.text())
|
||||
current_value = current_value + inc
|
||||
except ValueError:
|
||||
current_value = 0
|
||||
|
||||
self.ui.le_suffix.setText(str(current_value))
|
||||
|
||||
@Slot()
|
||||
def on_btn_suffix_inc_clicked(self):
|
||||
def on_btn_suffix_inc_clicked(self) -> None:
|
||||
self.calc_suffix(1)
|
||||
|
||||
@Slot()
|
||||
def on_btn_suffix_dec_clicked(self):
|
||||
def on_btn_suffix_dec_clicked(self) -> None:
|
||||
self.calc_suffix(-1)
|
||||
|
||||
@Slot()
|
||||
def on_btn_file_select_clicked(self):
|
||||
file, ok = QFileDialog.getOpenFileName(self, "Select File", self.ui.le_filepath.text())
|
||||
|
||||
if file == "":
|
||||
def on_btn_file_select_clicked(self) -> None:
|
||||
file, _ = QFileDialog.getOpenFileName(self, "Select File", self.ui.le_filepath.text())
|
||||
if not file:
|
||||
return
|
||||
|
||||
file_path, file_name = os.path.split(file)
|
||||
name, extension = os.path.splitext(file_name)
|
||||
|
||||
self.ui.le_filepath.setText(file_path)
|
||||
self.ui.le_fileprefix.setText(name)
|
||||
self.ui.le_suffix.setText("")
|
||||
@ -113,29 +108,22 @@ class ReadDiskWindow(QDialog):
|
||||
self.on_update_settings()
|
||||
|
||||
@Slot()
|
||||
def on_btn_path_select_clicked(self):
|
||||
def on_btn_path_select_clicked(self) -> None:
|
||||
path = QFileDialog.getExistingDirectory(self, "Select Folder")
|
||||
self.ui.le_filepath.setText(path)
|
||||
self.on_update_settings()
|
||||
if path:
|
||||
self.ui.le_filepath.setText(path)
|
||||
self.on_update_settings()
|
||||
|
||||
@Slot()
|
||||
def on_launch(self):
|
||||
try:
|
||||
completed = subprocess.run(self.command, check=True)
|
||||
except FileNotFoundError as e:
|
||||
QMessageBox.critical(self, "Error", f"Command not found: {e}")
|
||||
except subprocess.CalledProcessError as e:
|
||||
QMessageBox.critical(self, "Error", f"Failed to launch command: {e}")
|
||||
def on_cb_fake_index_toggled(self, checked: bool) -> None:
|
||||
"""Enables or disables the Fake Index widgets."""
|
||||
self.ui.le_fake_index.setEnabled(checked)
|
||||
self.ui.combo_fake_index.setEnabled(checked)
|
||||
self.on_update_settings()
|
||||
|
||||
if self.ui.cb_inc.isChecked():
|
||||
self.calc_suffix(1)
|
||||
|
||||
def get_settings(self):
|
||||
"""
|
||||
A helper method to gather all settings from the UI into a dictionary.
|
||||
This is a clean way to pass the data out of the dialog.
|
||||
"""
|
||||
settings = {
|
||||
def get_settings(self) -> dict:
|
||||
"""Gather all settings from the UI into a dictionary."""
|
||||
return {
|
||||
"fileprefix": self.ui.le_fileprefix.text(),
|
||||
"filepath": self.ui.le_filepath.text(),
|
||||
"double_step_enabled": self.ui.cb_double_step.isChecked(),
|
||||
@ -170,7 +158,7 @@ class ReadDiskWindow(QDialog):
|
||||
"pin2_low": self.ui.rb_pin2_low.isChecked(),
|
||||
"flippy_enabled": self.ui.cb_flippy.isChecked(),
|
||||
"flippy_panasonic": self.ui.rb_panasonic.isChecked(),
|
||||
"flippy_teac": self.ui.rb_teac.isChecked(),'"' +
|
||||
"flippy_teac": self.ui.rb_teac.isChecked(),
|
||||
"adjust_speed_enabled": self.ui.cb_adjust_speed.isChecked(),
|
||||
"adjust_speed_value": self.ui.le_adjust_speed.text(),
|
||||
"adjust_speed_unit": self.ui.combo_adjust_speed.currentText(),
|
||||
@ -181,9 +169,8 @@ class ReadDiskWindow(QDialog):
|
||||
"disktype_value": self.ui.combo_disktype.currentText(),
|
||||
}
|
||||
|
||||
return settings
|
||||
|
||||
def set_settings(self, settings):
|
||||
def set_settings(self, settings: dict) -> None:
|
||||
"""Apply a settings dictionary to the UI."""
|
||||
self.ui.le_fileprefix.setText(settings.get("fileprefix", ""))
|
||||
self.ui.le_filepath.setText(settings.get("filepath", ""))
|
||||
self.ui.cb_double_step.setChecked(settings.get("double_step_enabled", False))
|
||||
@ -228,124 +215,103 @@ class ReadDiskWindow(QDialog):
|
||||
self.ui.combo_format.setCurrentText(settings.get("format_value", ""))
|
||||
self.ui.combo_disktype.setCurrentText(settings.get("disktype_value", ""))
|
||||
# Note: command is not set here, as it is generated from UI state
|
||||
self.device = settings.get("device", "")
|
||||
self.on_update_settings()
|
||||
|
||||
def on_update_settings(self, *args, **kwargs):
|
||||
def build_command(self) -> tuple[list, str]:
|
||||
"""Build the command list based on the current UI state."""
|
||||
fileprefix = self.ui.le_fileprefix.text()
|
||||
drive = ""
|
||||
bitrate = ""
|
||||
legacy_ss = ""
|
||||
revs = ""
|
||||
retries = ""
|
||||
fake_index = ""
|
||||
drive = f"--drive={self.ui.combo_drive_select.currentText()}" if self.ui.cb_drive_select.isChecked() else ""
|
||||
bitrate = f"::bitrate={self.ui.le_bitrate.text()}" if self.ui.cb_bitrate.isChecked() else ""
|
||||
legacy_ss = "::legacy_ss" if self.ui.cb_ss_legacy.isChecked() else ""
|
||||
revs = f"--revs={self.ui.le_revs.text()}" if self.ui.cb_revs.isChecked() else ""
|
||||
retries = f"--retries={self.ui.le_retries.text()}" if self.ui.cb_retries.isChecked() else ""
|
||||
fake_index = f"--fake-index={self.ui.le_fake_index.text()}{self.ui.combo_fake_index.currentText()}" if self.ui.cb_fake_index.isChecked() else ""
|
||||
pll = ""
|
||||
tracks = ""
|
||||
densel = ""
|
||||
no_clobber = ""
|
||||
raw = ""
|
||||
reverse = ""
|
||||
hard_sectors = ""
|
||||
adjust_speed = ""
|
||||
disktype = ""
|
||||
|
||||
if self.ui.cb_revs.isChecked():
|
||||
revs = "--revs=" + self.ui.le_revs.text()
|
||||
|
||||
if self.ui.cb_drive_select.isChecked():
|
||||
drive = "--drive=" + self.ui.combo_drive_select.currentText()
|
||||
|
||||
if self.ui.cb_bitrate.isChecked():
|
||||
bitrate = "::bitrate=" + self.ui.le_bitrate.text()
|
||||
|
||||
if self.ui.cb_ss_legacy.isChecked():
|
||||
legacy_ss = "::legacy_ss"
|
||||
|
||||
if self.ui.cb_retries.isChecked():
|
||||
retries = "--retries=" + self.ui.le_retries.text()
|
||||
|
||||
if self.ui.cb_fake_index.isChecked(): command = " ".join(self.command)
|
||||
|
||||
|
||||
fake_index = "--fake-index=" + self.ui.le_fake_index.text() + self.ui.combo_fake_index.currentText()
|
||||
|
||||
if self.ui.cb_pllspec.isChecked():
|
||||
pll = "--pll=period=" + self.ui.le_period.text() + ":phase=m" + self.ui.le_phase.text()
|
||||
|
||||
if self.ui.le_lowpass.text() != "":
|
||||
pll = pll + ":lowpass=" + self.ui.le_lowpass.text()
|
||||
|
||||
# --tracks combines multiple settings into a single argument
|
||||
if self.ui.cb_double_step.isChecked():
|
||||
tracks = "step=" + self.ui.le_double_step.text()
|
||||
|
||||
if self.ui.cb_cylinder_sets.isChecked():
|
||||
if tracks != "":
|
||||
tracks = tracks + ":"
|
||||
|
||||
tracks = tracks + "c=" + self.ui.le_cylinder_sets.text()
|
||||
|
||||
if self.ui.cb_head_sets.isChecked():
|
||||
if tracks != "":
|
||||
tracks = tracks + ":"
|
||||
|
||||
tracks = tracks + "h=" + self.ui.le_head_sets.text()
|
||||
|
||||
if self.ui.cb_head_swap.isChecked():
|
||||
if tracks != "":
|
||||
tracks = tracks + ":"
|
||||
|
||||
tracks = tracks + "hswap"
|
||||
|
||||
if self.ui.cb_flippy.isChecked():
|
||||
if tracks != "":
|
||||
tracks = tracks + ":"
|
||||
|
||||
if self.ui.rb_panasonic.isChecked():
|
||||
tracks = tracks + "h1.off=-8"
|
||||
else:
|
||||
tracks = tracks + "h0.off=+8"
|
||||
|
||||
if tracks != "":
|
||||
tracks = "--tracks=" + tracks
|
||||
|
||||
if self.ui.cb_rev_track_data.isChecked():
|
||||
reverse = "--reverse"
|
||||
|
||||
if self.ui.cb_hard_sectors.isChecked():
|
||||
hard_sectors = "--hard-sectors"
|
||||
|
||||
if self.ui.cb_no_clobber.isChecked():
|
||||
no_clobber = "--no-clobber"
|
||||
|
||||
pll = f"--pll=period={self.ui.le_period.text()}:phase={self.ui.le_phase.text()}"
|
||||
if self.ui.le_lowpass.text():
|
||||
pll += f":lowpass={self.ui.le_lowpass.text()}"
|
||||
tracks = self._build_tracks()
|
||||
reverse = "--reverse" if self.ui.cb_rev_track_data.isChecked() else ""
|
||||
hard_sectors = "--hard-sectors" if self.ui.cb_hard_sectors.isChecked() else ""
|
||||
no_clobber = "--no-clobber" if self.ui.cb_no_clobber.isChecked() else ""
|
||||
densel = ""
|
||||
if self.ui.cb_pin2.isChecked():
|
||||
if self.ui.rb_pin2_high.isChecked():
|
||||
densel = "--densel H"
|
||||
else:
|
||||
densel = "--densel L"
|
||||
|
||||
if self.ui.cb_raw.isChecked():
|
||||
raw = "--raw"
|
||||
|
||||
if self.ui.cb_adjust_speed.isChecked():
|
||||
adjust_speed = "--adjust-speed=" + self.ui.le_adjust_speed.text() + self.ui.combo_adjust_speed.currentText()
|
||||
|
||||
suffix = self.ui.le_suffix.text()
|
||||
|
||||
if suffix != "":
|
||||
suffix = "-" + suffix
|
||||
|
||||
densel = "--densel H" if self.ui.rb_pin2_high.isChecked() else "--densel L"
|
||||
raw = "--raw" if self.ui.cb_raw.isChecked() else ""
|
||||
adjust_speed = f"--adjust-speed={self.ui.le_adjust_speed.text()}{self.ui.combo_adjust_speed.currentText()}" if self.ui.cb_adjust_speed.isChecked() else ""
|
||||
suffix = f"-{self.ui.le_suffix.text()}" if self.ui.le_suffix.text() else ""
|
||||
filepath = self.ui.le_filepath.text()
|
||||
|
||||
disktype = self.ui.combo_disktype.currentText()
|
||||
generated_filename = fileprefix + suffix + disktype
|
||||
filename = os.path.join(filepath, generated_filename) + bitrate + legacy_ss
|
||||
|
||||
self.command = [
|
||||
format = f"--format={self.ui.combo_format.currentText()}" if self.ui.combo_format.currentText() else ""
|
||||
generated_filename = f"{fileprefix}{suffix}{disktype}"
|
||||
filename = os.path.join(filepath, generated_filename) + legacy_ss + bitrate
|
||||
device = f"--device={self.device}" if self.device and self.device != "Auto" else ""
|
||||
command = [
|
||||
item for item in [
|
||||
"gw", "read", tracks, revs, drive, densel,
|
||||
adjust_speed, no_clobber, raw, reverse,
|
||||
"./gw.sh", "read", tracks, revs, device, drive, densel,
|
||||
format, adjust_speed, no_clobber, raw, reverse,
|
||||
hard_sectors, fake_index, pll, retries, filename
|
||||
] if item
|
||||
]
|
||||
return command, generated_filename
|
||||
|
||||
def _build_tracks(self) -> str:
|
||||
"""Build the --tracks argument from relevant UI fields."""
|
||||
tracks = []
|
||||
if self.ui.cb_double_step.isChecked():
|
||||
tracks.append(f"step={self.ui.le_double_step.text()}")
|
||||
if self.ui.cb_cylinder_sets.isChecked():
|
||||
tracks.append(f"c={self.ui.le_cylinder_sets.text()}")
|
||||
if self.ui.cb_head_sets.isChecked():
|
||||
tracks.append(f"h={self.ui.le_head_sets.text()}")
|
||||
if self.ui.cb_head_swap.isChecked():
|
||||
tracks.append("hswap")
|
||||
if self.ui.cb_flippy.isChecked():
|
||||
if self.ui.rb_panasonic.isChecked():
|
||||
tracks.append("h1.off=-8")
|
||||
else:
|
||||
tracks.append("h0.off=+8")
|
||||
return f"--tracks={':'.join(tracks)}" if tracks else ""
|
||||
|
||||
def on_update_settings(self, *args, **kwargs) -> None:
|
||||
"""Update the command and filename fields based on current UI state."""
|
||||
self.command, generated_filename = self.build_command()
|
||||
self.ui.le_filename.setText(generated_filename)
|
||||
self.ui.te_command_line.setPlainText(" ".join(self.command))
|
||||
|
||||
@Slot()
|
||||
def on_launch(self) -> None:
|
||||
"""Run the constructed command using subprocess.Popen and write output to the console widget."""
|
||||
self.ui.btn_abort.setEnabled(True)
|
||||
self.ui.te_console.clear()
|
||||
self.abort = False
|
||||
|
||||
try:
|
||||
process = subprocess.Popen(
|
||||
self.command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
bufsize=1
|
||||
)
|
||||
if process.stdout:
|
||||
for line in iter(process.stdout.readline, ''):
|
||||
self.ui.te_console.append(line.rstrip())
|
||||
QCoreApplication.processEvents()
|
||||
if self.abort:
|
||||
process.terminate()
|
||||
self.ui.te_console.append("*** Aborted")
|
||||
break
|
||||
|
||||
process.wait()
|
||||
|
||||
if process.returncode == 0 and self.ui.cb_inc.isChecked():
|
||||
self.calc_suffix(1)
|
||||
except FileNotFoundError as e:
|
||||
QMessageBox.critical(self, "Error", f"Command not found: {e}")
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "Error", f"Failed to launch command: {e}")
|
||||
|
||||
self.ui.btn_abort.setEnabled(False)
|
||||
|
||||
Reference in New Issue
Block a user