diff --git a/floppyemu/__init__.py b/floppyemu/__init__.py --- a/floppyemu/__init__.py +++ b/floppyemu/__init__.py @@ -4,6 +4,8 @@ import os SINGLE_DISK_OFFSET = 1572864 MAX_IMAGES_ON_DRIVE = 1000 +LABEL_START_OFFSET = 0x2B +LABEL_LENGTH = 11 def get_or_create_empty_image(index, temp_path, size=1440): @@ -15,6 +17,8 @@ def get_or_create_empty_image(index, tem proc = subprocess.Popen(['mkfs.msdos', '-C', filename, str(size)]) rval = proc.wait() if rval != 0: + print(proc.stdout.read()) + print(proc.stderr.read()) raise Exception('Not created') return filename @@ -98,10 +102,21 @@ def list_images(device): # As an additional precaution check fs type. # If it's valid, then get label, otherwise consider disk unlabeled if bootsector[0x36:0x3E] in (b'FAT12 ', b'FAT16 ', b'FAT '): - label = bootsector[0x2B:0x36].decode(encoding='cp1251') + label = bootsector[LABEL_START_OFFSET:LABEL_START_OFFSET + LABEL_LENGTH].decode( + encoding='cp1251' + ) dfile.seek(SINGLE_DISK_OFFSET - 512, 1) else: disksize = 0 dfile.seek(SINGLE_DISK_OFFSET - 512, 1) rval.append((label, disksize)) return rval + + +def update_label(device, index, label): + offset = SINGLE_DISK_OFFSET * index + label = label[0:11] + label = label + ' ' * (LABEL_LENGTH - len(label)) + with open(device, 'wb') as dfile: + dfile.seek(offset + LABEL_START_OFFSET, 0) + dfile.write(label.encode(encoding='cp1251')) diff --git a/forms/mainwindow.py b/forms/mainwindow.py --- a/forms/mainwindow.py +++ b/forms/mainwindow.py @@ -26,6 +26,7 @@ class CustomListModel(QtCore.QStringList class CustomTableModel(QtCore.QAbstractTableModel): headers = ['Label', 'Size'] + edited = QtCore.pyqtSignal(int, str) def __init__(self, placeholder): super().__init__() @@ -37,8 +38,31 @@ class CustomTableModel(QtCore.QAbstractT self.model = model self.endResetModel() + def flags(self, index): + if not index.isValid(): + return QtCore.Qt.ItemIsEnabled + + if index.column() == 0: + return int(super().flags(index)) | QtCore.Qt.ItemIsEditable + + return super().flags(index) + + def setData(self, index, value, role): + if index.isValid() and role == QtCore.Qt.EditRole: + self.edited.emit(index.row(), value) + return True + + return False + + def data(self, index, role=QtCore.Qt.DisplayRole): model = self.model[index.row()] + if role == QtCore.Qt.EditRole: + if QtCore.QVariant(model[index.column()]): + if index.column() == 0: + return QtCore.QVariant(model[index.column()]) + + return QtCore.QVariant(None) if role == QtCore.Qt.DisplayRole: if QtCore.QVariant(model[index.column()]): if index.column() == 1: @@ -72,12 +96,14 @@ class MainWindow(Ui_MainWindow, QtWidget self.devices_model = CustomListModel() self.table_model = CustomTableModel('(Not set)') + self.table_model.edited.connect(self.table_edited) self.devices_combobox.setModel(self.devices_model) self.refresh_disk_drives() self.tableView.setModel(self.table_model) - self.refresh_image_list() + self.tableView.doubleClicked.connect(self.table_double_click) + self.on_device_change() self.action_refresh_devices.triggered.connect(self.refresh_disk_drives) self.devices_combobox.currentIndexChanged.connect(self.on_device_change) @@ -89,20 +115,34 @@ class MainWindow(Ui_MainWindow, QtWidget self.action_format_usb.triggered.connect(self.format_many) self.action_about.triggered.connect(self.show_about_dialog) + @property + def current_device(self): + if self.devices_combobox.currentIndex() != -1: + return '/dev/{}'.format(self.devices_model.getItem(self.devices_combobox.currentIndex())[0]) + else: + return None + + def table_edited(self, index, value): + if self.current_device: + floppyemu.update_label(self.current_device, index, value) + self.refresh_image_list() + + + def table_double_click(self, index): + self.tableView.edit(index) + def show_about_dialog(self): AboutWidget().exec_() def format_one(self): - if self.devices_combobox.currentIndex() != -1: + if self.current_device: indexes = self.tableView.selectedIndexes() - device = '/dev/{}'.format(self.devices_model.getItem(self.devices_combobox.currentIndex())[0]) - FormatOneDialog.show_dialog(indexes[0].row(), device, os.path.join(self.root, 'temp')) + FormatOneDialog.show_dialog(indexes[0].row(), self.current_device, os.path.join(self.root, 'temp')) self.refresh_image_list() def format_many(self): - if self.devices_combobox.currentIndex() != -1: - device = '/dev/{}'.format(self.devices_model.getItem(self.devices_combobox.currentIndex())[0]) - FormatManyDialog.show_dialog(device, os.path.join(self.root, 'temp')) + if self.current_device: + FormatManyDialog.show_dialog(self.current_device, os.path.join(self.root, 'temp')) self.refresh_image_list() def refresh_disk_drives(self): @@ -129,21 +169,19 @@ class MainWindow(Ui_MainWindow, QtWidget def refresh_image_list(self): try: - if self.devices_combobox.currentIndex() != -1: - device = '/dev/{}'.format(self.devices_model.getItem(self.devices_combobox.currentIndex())[0]) - m = floppyemu.list_images(device) + if self.current_device: + m = floppyemu.list_images(self.current_device) self.table_model.setModel(m) except PermissionError: - device = '/dev/{}'.format(self.devices_model.getItem(self.devices_combobox.currentIndex())[0]) QtWidgets.QMessageBox.critical( self, 'Permission error', - 'You have no access to the device %s. Please restart program as user with proper rights' % device + 'You have no access to the device %s. ' + 'Please restart program as user with proper rights' % self.current_device ) def open_directory(self): try: - if self.devices_combobox.currentIndex() != -1: - device = '/dev/{}'.format(self.devices_model.getItem(self.devices_combobox.currentIndex())[0]) + if self.current_device: indexes = self.tableView.selectedIndexes() for index in indexes: image = os.path.join(self.root, 'temp/image{}.img'.format(index.row())) @@ -151,7 +189,7 @@ class MainWindow(Ui_MainWindow, QtWidget MountManager.get().unmount(image) if os.path.exists(image): os.remove(image) - floppyemu.read_image(device, image, index.row()) + floppyemu.read_image(self.current_device, image, index.row()) os.makedirs(os.path.join(self.root, 'folders/{}'.format(index.row())), exist_ok=True) os.chmod(os.path.join(self.root, 'folders/{}'.format(index.row())), stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) @@ -163,14 +201,13 @@ class MainWindow(Ui_MainWindow, QtWidget traceback.print_exc() def save_directory(self): - if self.devices_combobox.currentIndex() != -1: - device = '/dev/{}'.format(self.devices_model.getItem(self.devices_combobox.currentIndex())[0]) + if self.current_device: indexes = self.tableView.selectedIndexes() for index in indexes: image = os.path.join(self.root, 'temp/image{}.img'.format(index.row())) if MountManager.get().is_mounted(image): MountManager.get().unmount(image) - floppyemu.write_image(device, image, index.row()) + floppyemu.write_image(self.current_device, image, index.row()) shutil.rmtree(os.path.join(self.root, 'folders/{}'.format(index.row()))) else: QtWidgets.QMessageBox.critical( @@ -181,8 +218,7 @@ class MainWindow(Ui_MainWindow, QtWidget self.refresh_image_list() def write_image(self): - if self.devices_combobox.currentIndex() != -1: - device = '/dev/{}'.format(self.devices_model.getItem(self.devices_combobox.currentIndex())[0]) + if self.current_device: indexes = self.tableView.selectedIndexes() for index in indexes: fd = QtWidgets.QFileDialog(self) @@ -190,15 +226,14 @@ class MainWindow(Ui_MainWindow, QtWidget fd.setWindowTitle('Select file for image {}'.format(index.row())) if fd.exec() == QtWidgets.QDialog.Accepted: image = fd.selectedFiles()[0] - floppyemu.write_image(device, image, index.row()) + floppyemu.write_image(self.current_device, image, index.row()) else: return self.refresh_image_list() def read_image(self): - if self.devices_combobox.currentIndex() != -1: - device = '/dev/{}'.format(self.devices_model.getItem(self.devices_combobox.currentIndex())[0]) + if self.current_device: indexes = self.tableView.selectedIndexes() for index in indexes: fd = QtWidgets.QFileDialog(self) @@ -206,7 +241,7 @@ class MainWindow(Ui_MainWindow, QtWidget fd.setWindowTitle('Select file for image {}'.format(index.row())) if fd.exec() == QtWidgets.QDialog.Accepted: image = fd.selectedFiles()[0] - floppyemu.read_image(device, image, index.row()) + floppyemu.read_image(self.current_device, image, index.row()) else: return @@ -218,4 +253,4 @@ class MainWindow(Ui_MainWindow, QtWidget QtWidgets.QMessageBox.critical( self, 'Error', 'Unable to clean up. Some resources are in use: {}'.format(e) - ) \ No newline at end of file + ) diff --git a/ui/about.py b/ui/about.py --- a/ui/about.py +++ b/ui/about.py @@ -27,4 +27,4 @@ class Ui_Form(object): def retranslateUi(self, Form): _translate = QtCore.QCoreApplication.translate Form.setWindowTitle(_translate("Form", "About KUSBFloppyFormatter")) - self.label.setText(_translate("Form", "

USB Floppy Formatter

Version 1.0

By: Khaelenmore Thaal


GUI utility for formatting thumb drives for usage with hardware usb emulators
Uses Qt5
https://www.qt.io/
Uses PyQt5
https://www.riverbankcomputing.com/software/pyqt/intro
Built-in icons by
http://www.fatcow.com/free-icons
This program is licensed with GNU GPL v3
This program is available on
http://silverwing.one/pages/kusbff

")) + self.label.setText(_translate("Form", "

USB Floppy Formatter

Version 1.0.2

By: Khaelenmore Thaal


GUI utility for formatting thumb drives for usage with hardware usb emulators
Uses Qt5
https://www.qt.io/
Uses PyQt5
https://www.riverbankcomputing.com/software/pyqt/intro
Built-in icons by
http://www.fatcow.com/free-icons
This program is licensed with GNU GPL v3
This program is available on
http://silverwing.one/pages/kusbff

"))