diff -r 331e717c458e -r 218ca8019eb8 eric6/MicroPython/UnknownDevicesDialog.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric6/MicroPython/UnknownDevicesDialog.py Sat Feb 06 19:17:25 2021 +0100 @@ -0,0 +1,256 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2021 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to manage the list of unknown devices. +""" + +from PyQt5.QtCore import pyqtSlot, Qt, QUrl, QUrlQuery +from PyQt5.QtGui import QDesktopServices +from PyQt5.QtWidgets import QDialog, QListWidgetItem + +from E5Gui import E5MessageBox + +from .Ui_UnknownDevicesDialog import Ui_UnknownDevicesDialog + +import Preferences +from UI.Info import BugAddress + + +class UnknownDevicesDialog(QDialog, Ui_UnknownDevicesDialog): + """ + Class implementing a dialog to manage the list of unknown devices. + """ + DeviceDataRole = Qt.UserRole + ModifiedRole = Qt.UserRole + 1 + + def __init__(self, parent=None): + """ + Constructor + + @param parent reference to the parent widget (defaults to None) + @type QWidget (optional) + """ + super(UnknownDevicesDialog, self).__init__(parent) + self.setupUi(self) + + self.__loadDevices() + + def __loadDevices(self): + """ + Private method to load the list of unknown devices. + """ + self.deviceList.clear() + + devices = Preferences.getMicroPython("ManualDevices") + for device in devices: + itm = QListWidgetItem( + self.tr("{0} (0x{1:04x}/0x{2:04x})", "description, VID, PID") + .format(device["description"], device["vid"], device["pid"]), + self.deviceList) + itm.setData(self.DeviceDataRole, device) + itm.setData(self.ModifiedRole, False) + + self.__initialDeviceCount = self.deviceList.count() + + self.__checkButtons() + + def __isDirty(self): + """ + Private method to check, if the dialog contains unsaved data. + + @return flag indicating the presence of unsaved data + @rtype bool + """ + dirty = False + for row in range(self.deviceList.count()): + dirty |= self.deviceList.item(row).data(self.ModifiedRole) + dirty |= self.deviceList.count() != self.__initialDeviceCount + return dirty + + def __editItem(self, item): + """ + Private method to edit the given item. + + @param item reference to the item to be edited + @type QListWidgetItem + """ + if item is None: + # play it safe + return + + from .AddEditDevicesDialog import AddEditDevicesDialog + dlg = AddEditDevicesDialog(deviceData=item.data(self.DeviceDataRole)) + if dlg.exec() == QDialog.Accepted: + deviceDict = dlg.getDeviceDict() + item.setData(self.DeviceDataRole, deviceDict) + item.setData(self.ModifiedRole, True) + + item.setText(self.tr("{0} (*)", "list entry is modified") + .format(item.text())) + + def __saveDeviceData(self): + """ + Private method to save the device data. + """ + devices = [] + + for row in range(self.deviceList.count()): + devices.append(self.deviceList.item(row).data( + self.DeviceDataRole)) + Preferences.setMicroPython("ManualDevices", devices) + + return True + + @pyqtSlot() + def __checkButtons(self): + """ + Private slot to set the enabled state of the buttons. + """ + selectedItemsCount = len(self.deviceList.selectedItems()) + self.editButton.setEnabled(selectedItemsCount == 1) + self.deleteButton.setEnabled(selectedItemsCount >= 1) + + @pyqtSlot(QListWidgetItem) + def on_deviceList_itemActivated(self, item): + """ + Private slot to edit the data of the activated item. + + @param item reference to the activated item + @type QListWidgetItem + """ + self.__editItem(item) + + @pyqtSlot() + def on_deviceList_itemSelectionChanged(self): + """ + Private slot to handle a change of selected items. + """ + self.__checkButtons() + + @pyqtSlot() + def on_editButton_clicked(self): + """ + Private slot to edit the selected item. + """ + itm = self.deviceList.selectedItems()[0] + self.__editItem(itm) + + @pyqtSlot() + def on_deleteButton_clicked(self): + """ + Private slot to delete the selected entries. + """ + unsaved = False + for itm in self.deviceList.selectedItems(): + unsaved |= itm.data(self.ModifiedRole) + if unsaved: + ok = E5MessageBox.yesNo( + self, + self.tr("Delete Unknown Devices"), + self.tr("The selected entries contain some with modified" + " data. Shall they really be deleted?")) + if not ok: + return + + for itm in self.deviceList.selectedItems(): + self.deviceList.takeItem(self.deviceList.row(itm)) + del itm + + @pyqtSlot() + def on_deleteAllButton_clicked(self): + """ + Private slot to delete all devices. + """ + if self.__isDirty(): + ok = E5MessageBox.yesNo( + self, + self.tr("Delete Unknown Devices"), + self.tr("The list contains some devices with modified" + " data. Shall they really be deleted?")) + if not ok: + return + + self.deviceList.clear() + + @pyqtSlot() + def on_restoreButton_clicked(self): + """ + Private slot to restore the list of unknown devices. + """ + if self.__isDirty(): + ok = E5MessageBox.yesNo( + self, + self.tr("Restore Unknown Devices"), + self.tr("Restoring the list of unknown devices will overwrite" + " all changes made. Do you really want to restore the" + " list?")) + if not ok: + return + + self.__loadDevices() + + @pyqtSlot() + def on_reportButton_clicked(self): + """ + Private slot to report the data of all boards to the eric-bugs email + address. + """ + if self.deviceList.count() > 0: + bodyList = [ + "These are my MicroPython devices not yet known by eric." + " Please add them.", + "", + ] + + for row in range(self.deviceList.count()): + deviceDict = self.deviceList.item(row).data( + self.DeviceDataRole) + bodyList += [ + "Board #{0}:".format(row), + " VID: {0}".format(deviceDict["vid"]), + " PID: {0}".format(deviceDict["pid"]), + " Description: {0}".format(deviceDict["description"]), + " Device Type: {0}".format(deviceDict["type"]), + " Data Volume: {0}".format(deviceDict["data_volume"]), + " Flash Volume: {0}".format(deviceDict["flash_volume"]), + "" + ] + + urlQuery = QUrlQuery() + urlQuery.addQueryItem("subject", "Unsupported MicroPython Devices") + urlQuery.addQueryItem("body", "\r\n".join(bodyList)) + + url = QUrl("mailto:{0}".format(BugAddress)) + url.setQuery(urlQuery) + + QDesktopServices.openUrl(url) + + @pyqtSlot() + def on_buttonBox_accepted(self): + """ + Private slot to handle the OK button press. + + This action saves the edited list to the preferences store. + """ + self.__saveDeviceData() + self.accept() + + @pyqtSlot() + def on_buttonBox_rejected(self): + """ + Private slot handling the cancellation of the dialog. + """ + if self.__isDirty(): + ok = E5MessageBox.okToClearData( + self, + self.tr("Unsaved Data"), + self.tr("""The list of devices contains some with modified""" + """ data."""), + self.__saveDeviceData) + if not ok: + return + + self.reject()