Files @ 8f2355969e7e
Branch filter:

Location: linux-tools/kusbff/forms/mainwindow.py - annotation

Silverwing
Editing labels; Fix inability to format images without initial device change; a little bit of refactoring
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
8f2355969e7e
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
f3f4cf108453
f3f4cf108453
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
2e3b9132fe02
2e3b9132fe02
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
03b0b1263122
8f2355969e7e
03b0b1263122
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
8f2355969e7e
8f2355969e7e
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
8f2355969e7e
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
8f2355969e7e
f3f4cf108453
8f2355969e7e
f3f4cf108453
f3f4cf108453
f3f4cf108453
8f2355969e7e
8f2355969e7e
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
8f2355969e7e
8f2355969e7e
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
8f2355969e7e
8f2355969e7e
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
8f2355969e7e
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
8f2355969e7e
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
8f2355969e7e
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
8f2355969e7e
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
8f2355969e7e
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
8f2355969e7e
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
8f2355969e7e
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
8f2355969e7e
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
f3f4cf108453
8f2355969e7e
from forms.about import AboutWidget
from ui.mainwindow import Ui_MainWindow
from PyQt5 import QtWidgets, QtCore, QtGui
from devices import get_storage_devices
from mount.udisks import MountManager
import tempfile
import os
import shutil
import stat
import floppyemu
from .format_dlgs import FormatManyDialog, FormatOneDialog


class CustomListModel(QtCore.QStringListModel):
    def __init__(self, model=()):
        self.model = model
        super().__init__([m[1] for m in self.model])

    def setModel(self, model):
        self.model = model
        self.setStringList([m[1] for m in self.model])

    def getItem(self, index):
        return self.model[index]


class CustomTableModel(QtCore.QAbstractTableModel):
    headers = ['Label', 'Size']
    edited = QtCore.pyqtSignal(int, str)

    def __init__(self, placeholder):
        super().__init__()
        self.placeholder = placeholder
        self.model = []

    def setModel(self, model):
        self.beginResetModel()
        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:
                    return QtCore.QVariant(str(round(model[index.column()] / 1024, 2)) + 'KB')
                else:
                    return QtCore.QVariant(model[index.column()])
            else:
                return QtCore.QVariant(self.placeholder)

    def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
        if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
            return QtCore.QVariant(self.headers[section])
        elif orientation == QtCore.Qt.Vertical and role == QtCore.Qt.DisplayRole:
            return QtCore.QVariant(section)
        return super().headerData(section, orientation, role)

    def rowCount(self, parent=None):
        return len(self.model)

    def columnCount(self, parent=None):
        return 2


class MainWindow(Ui_MainWindow, QtWidgets.QMainWindow):
    def __init__(self, root=None):
        super().__init__()
        self.setupUi(self)

        self.root = root if root else tempfile.mktemp(prefix='kusbff_')
        os.makedirs(self.root, exist_ok=True)

        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.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)
        self.action_open_floppy.triggered.connect(self.open_directory)
        self.action_write_floppy.triggered.connect(self.save_directory)
        self.action_read_image.triggered.connect(self.read_image)
        self.action_write_image.triggered.connect(self.write_image)
        self.action_format_disk.triggered.connect(self.format_one)
        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.current_device:
            indexes = self.tableView.selectedIndexes()
            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.current_device:
            FormatManyDialog.show_dialog(self.current_device, os.path.join(self.root, 'temp'))
            self.refresh_image_list()

    def refresh_disk_drives(self):
        self.devices_model.setModel(get_storage_devices(True, 'disk'))
        self.refresh_image_list()

    def clean(self):
        MountManager.get().dispose_all()
        if os.path.exists(self.root):
            shutil.rmtree(self.root)

    def on_device_change(self):
        # Unmount and remove all old images
        MountManager.get().dispose_all()
        if os.path.exists(os.path.join(self.root, 'temp')):
            for f in os.listdir(os.path.join(self.root, 'temp')):
                if os.path.isfile(os.path.join(self.root, 'temp', f)):
                    os.remove(os.path.join(self.root, 'temp', f))
                else:
                    shutil.rmtree(os.path.join(self.root, 'temp', f))

        os.makedirs(os.path.join(self.root, 'temp'), exist_ok=True)
        self.refresh_image_list()

    def refresh_image_list(self):
        try:
            if self.current_device:
                m = floppyemu.list_images(self.current_device)
                self.table_model.setModel(m)
        except PermissionError:
            QtWidgets.QMessageBox.critical(
                self, 'Permission error',
                '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.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)
                    if os.path.exists(image):
                        os.remove(image)
                    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)
                    folder_path = MountManager.get().mount(image)
                    QtGui.QDesktopServices.openUrl(
                        QtCore.QUrl.fromLocalFile(os.path.join(self.root, folder_path)))
        except:
            import traceback
            traceback.print_exc()

    def save_directory(self):
        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(self.current_device, image, index.row())
                    shutil.rmtree(os.path.join(self.root, 'folders/{}'.format(index.row())))
                else:
                    QtWidgets.QMessageBox.critical(
                        self, 'Error',
                        'Directory does not exist'
                    )

        self.refresh_image_list()

    def write_image(self):
        if self.current_device:
            indexes = self.tableView.selectedIndexes()
            for index in indexes:
                fd = QtWidgets.QFileDialog(self)
                fd.setAcceptMode(QtWidgets.QFileDialog.AcceptOpen)
                fd.setWindowTitle('Select file for image {}'.format(index.row()))
                if fd.exec() == QtWidgets.QDialog.Accepted:
                    image = fd.selectedFiles()[0]
                    floppyemu.write_image(self.current_device, image, index.row())
                else:
                    return

        self.refresh_image_list()

    def read_image(self):
        if self.current_device:
            indexes = self.tableView.selectedIndexes()
            for index in indexes:
                fd = QtWidgets.QFileDialog(self)
                fd.setAcceptMode(QtWidgets.QFileDialog.AcceptSave)
                fd.setWindowTitle('Select file for image {}'.format(index.row()))
                if fd.exec() == QtWidgets.QDialog.Accepted:
                    image = fd.selectedFiles()[0]
                    floppyemu.read_image(self.current_device, image, index.row())
                else:
                    return

    def closeEvent(self, event: QtGui.QCloseEvent):
        try:
            self.clean()
        except Exception as e:
            event.ignore()
            QtWidgets.QMessageBox.critical(
                self, 'Error',
                'Unable to clean up. Some resources are in use: {}'.format(e)
            )