Thu, 25 May 2023 19:51:47 +0200
Corrected and checked some code style issues (unused function arguments).
# -*- coding: utf-8 -*- # Copyright (c) 2010 - 2023 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing a widget to show numbers in different formats. """ from PyQt6.QtCore import QAbstractTableModel, QModelIndex, Qt, pyqtSignal, pyqtSlot from PyQt6.QtWidgets import QHeaderView, QWidget from eric7.EricGui import EricPixmapCache from eric7.EricWidgets.EricApplication import ericApp from .Ui_NumbersWidget import Ui_NumbersWidget class BinaryModel(QAbstractTableModel): """ Class implementing a model for entering binary numbers. """ def __init__(self, parent=None): """ Constructor @param parent reference to the parent widget (QWidget) """ super().__init__(parent) self.__bits = 0 self.__value = 0 def rowCount(self, parent): # noqa: U100 """ Public method to get the number of rows of the model. @param parent parent index (QModelIndex) @return number of columns (integer) """ return 1 def columnCount(self, parent): # noqa: U100 """ Public method to get the number of columns of the model. @param parent parent index (QModelIndex) @return number of columns (integer) """ return self.__bits def data(self, index, role=Qt.ItemDataRole.DisplayRole): """ Public method to get data from the model. @param index index to get data for (QModelIndex) @param role role of the data to retrieve (integer) @return requested data """ if role == Qt.ItemDataRole.CheckStateRole: if (self.__value >> (self.__bits - index.column() - 1)) & 1: return Qt.CheckState.Checked else: return Qt.CheckState.Unchecked elif role == Qt.ItemDataRole.DisplayRole: return "" return None def flags(self, index): # noqa: U100 """ Public method to get flags from the model. @param index index to get flags for (QModelIndex) @return flags (Qt.ItemFlags) """ return ( Qt.ItemFlag.ItemIsUserCheckable | Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable ) def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole): """ Public method to get header data from the model. @param section section number (integer) @param orientation orientation (Qt.Orientation) @param role role of the data to retrieve (Qt.ItemDataRole) @return requested data """ if ( orientation == Qt.Orientation.Horizontal and role == Qt.ItemDataRole.DisplayRole ): return str(self.__bits - section - 1) return QAbstractTableModel.headerData(self, section, orientation, role) def setBits(self, bits): """ Public slot to set the number of bits. @param bits number of bits to show (integer) """ self.beginResetModel() self.__bits = bits self.endResetModel() def setValue(self, value): """ Public slot to set the value to show. @param value value to show (integer) """ self.beginResetModel() self.__value = value self.endResetModel() def setBitsAndValue(self, bits, value): """ Public slot to set the number of bits and the value to show. @param bits number of bits to show (integer) @param value value to show (integer) """ self.__bits = bits self.__value = value self.beginResetModel() self.endResetModel() def getValue(self): """ Public slot to get the current value. @return current value of the model (integer) """ return self.__value def setData(self, index, value, role=Qt.ItemDataRole.EditRole): """ Public method to set the data of a node cell. @param index index of the node cell (QModelIndex) @param value value to be set @param role role of the data (integer) @return flag indicating success (boolean) """ if role == Qt.ItemDataRole.CheckStateRole: if Qt.CheckState(value) == Qt.CheckState.Checked: self.__value |= 1 << self.__bits - index.column() - 1 else: self.__value &= ~(1 << self.__bits - index.column() - 1) self.dataChanged.emit(index, index) return True return False class NumbersWidget(QWidget, Ui_NumbersWidget): """ Class implementing a widget to show numbers in different formats. @signal insertNumber(str) emitted after the user has entered a number and selected the number format """ insertNumber = pyqtSignal(str) def __init__(self, parent=None): """ Constructor @param parent reference to the parent widget (QWidget) """ super().__init__(parent) self.setupUi(self) self.setWindowIcon(EricPixmapCache.getIcon("eric")) self.__badNumberSheet = ( "background-color: #b31b1b;" if ericApp().usesDarkPalette() else "background-color: #ffa0a0;" ) self.binInButton.setIcon(EricPixmapCache.getIcon("2downarrow")) self.binOutButton.setIcon(EricPixmapCache.getIcon("2uparrow")) self.octInButton.setIcon(EricPixmapCache.getIcon("2downarrow")) self.octOutButton.setIcon(EricPixmapCache.getIcon("2uparrow")) self.decInButton.setIcon(EricPixmapCache.getIcon("2downarrow")) self.decOutButton.setIcon(EricPixmapCache.getIcon("2uparrow")) self.hexInButton.setIcon(EricPixmapCache.getIcon("2downarrow")) self.hexOutButton.setIcon(EricPixmapCache.getIcon("2uparrow")) self.formatBox.addItem(self.tr("Auto"), 0) self.formatBox.addItem(self.tr("Dec"), 10) self.formatBox.addItem(self.tr("Hex"), 16) self.formatBox.addItem(self.tr("Oct"), 8) self.formatBox.addItem(self.tr("Bin"), 2) self.sizeBox.addItem("8", 8) self.sizeBox.addItem("16", 16) self.sizeBox.addItem("32", 32) self.sizeBox.addItem("64", 64) self.__input = 0 self.__inputValid = True self.__bytes = 1 self.__model = BinaryModel(self) self.binTable.setModel(self.__model) self.binTable.horizontalHeader().setSectionResizeMode( QHeaderView.ResizeMode.ResizeToContents ) self.__model.setBitsAndValue(self.__bytes * 8, self.__input) self.__model.dataChanged.connect(self.__binModelDataChanged) def __formatNumbers(self, numberFormat): """ Private method to format the various number inputs. @param numberFormat number format indicator (integer) """ self.__block(True) self.binEdit.setStyleSheet("") self.octEdit.setStyleSheet("") self.decEdit.setStyleSheet("") self.hexEdit.setStyleSheet("") # determine byte count byteCount = 8 tmp = self.__input for _ in range(8): c = (tmp & 0xFF00000000000000) >> 7 * 8 if c != 0 and self.__input >= 0: break if c != 0xFF and self.__input < 0: break tmp <<= 8 byteCount -= 1 if byteCount == 0: byteCount = 1 self.__bytes = byteCount bytesIn = self.sizeBox.itemData(self.sizeBox.currentIndex()) // 8 if bytesIn and byteCount > bytesIn: self.sizeBox.setStyleSheet(self.__badNumberSheet) else: self.sizeBox.setStyleSheet("") # octal if numberFormat != 8: self.octEdit.setText("{0:0{1}o}".format(self.__input, bytesIn * 3)) # decimal if numberFormat != 10: self.decEdit.setText("{0:d}".format(self.__input)) # hexadecimal if numberFormat != 16: self.hexEdit.setText("{0:0{1}x}".format(self.__input, bytesIn * 2)) # octal if numberFormat != 8: self.octEdit.setText("{0:0{1}o}".format(self.__input, bytesIn * 3)) # binary if numberFormat != 2: num = "{0:0{1}b}".format(self.__input, bytesIn * 8) self.binEdit.setText(num) self.__model.setBitsAndValue(len(self.binEdit.text()), self.__input) self.__block(False) def __block(self, b): """ Private slot to block some signals. @param b flah indicating the blocking state (boolean) """ self.hexEdit.blockSignals(b) self.decEdit.blockSignals(b) self.octEdit.blockSignals(b) self.binEdit.blockSignals(b) self.binTable.blockSignals(b) @pyqtSlot(int) def on_sizeBox_valueChanged(self, value): """ Private slot handling a change of the bit size. @param value selected bit size (integer) """ self.__formatNumbers(10) @pyqtSlot() def on_byteOrderButton_clicked(self): """ Private slot to swap the byte order. """ bytesIn = self.sizeBox.itemData(self.sizeBox.currentIndex()) // 8 if bytesIn == 0: bytesIn = self.__bytes tmp1 = self.__input tmp2 = 0 for _ in range(bytesIn): tmp2 <<= 8 tmp2 |= tmp1 & 0xFF tmp1 >>= 8 self.__input = tmp2 self.__formatNumbers(0) @pyqtSlot() def on_binInButton_clicked(self): """ Private slot to retrieve a binary number from the current editor. """ number = ericApp().getObject("ViewManager").getNumber() if number == "": return self.binEdit.setText(number) self.binEdit.setFocus() @pyqtSlot(str) def on_binEdit_textChanged(self, txt): """ Private slot to handle input of a binary number. @param txt text entered (string) """ try: self.__input = int(txt, 2) self.__inputValid = True except ValueError: self.__inputValid = False if self.__inputValid: self.__formatNumbers(2) else: self.binEdit.setStyleSheet(self.__badNumberSheet) @pyqtSlot() def on_binOutButton_clicked(self): """ Private slot to send a binary number. """ self.insertNumber.emit(self.binEdit.text()) @pyqtSlot(QModelIndex, QModelIndex) def __binModelDataChanged(self, start, end): """ Private slot to handle a change of the binary model value by the user. @param start start index (QModelIndex) @param end end index (QModelIndex) """ val = self.__model.getValue() bytesIn = self.sizeBox.itemData(self.sizeBox.currentIndex()) // 8 num = "{0:0{1}b}".format(val, bytesIn * 8) self.binEdit.setText(num) @pyqtSlot() def on_octInButton_clicked(self): """ Private slot to retrieve an octal number from the current editor. """ number = ericApp().getObject("ViewManager").getNumber() if number == "": return self.octEdit.setText(number) self.octEdit.setFocus() @pyqtSlot(str) def on_octEdit_textChanged(self, txt): """ Private slot to handle input of an octal number. @param txt text entered (string) """ try: self.__input = int(txt, 8) self.__inputValid = True except ValueError: self.__inputValid = False if self.__inputValid: self.__formatNumbers(8) else: self.octEdit.setStyleSheet(self.__badNumberSheet) @pyqtSlot() def on_octOutButton_clicked(self): """ Private slot to send an octal number. """ self.insertNumber.emit(self.octEdit.text()) @pyqtSlot() def on_decInButton_clicked(self): """ Private slot to retrieve a decimal number from the current editor. """ number = ericApp().getObject("ViewManager").getNumber() if number == "": return self.decEdit.setText(number) self.decEdit.setFocus() @pyqtSlot(str) def on_decEdit_textChanged(self, txt): """ Private slot to handle input of a decimal number. @param txt text entered (string) """ try: self.__input = int(txt, 10) self.__inputValid = True except ValueError: self.__inputValid = False if self.__inputValid: self.__formatNumbers(10) else: self.decEdit.setStyleSheet(self.__badNumberSheet) @pyqtSlot() def on_decOutButton_clicked(self): """ Private slot to send a decimal number. """ self.insertNumber.emit(self.decEdit.text()) @pyqtSlot() def on_hexInButton_clicked(self): """ Private slot to retrieve a hexadecimal number from the current editor. """ number = ericApp().getObject("ViewManager").getNumber() if number == "": return self.hexEdit.setText(number) self.hexEdit.setFocus() @pyqtSlot(str) def on_hexEdit_textChanged(self, txt): """ Private slot to handle input of a hexadecimal number. @param txt text entered (string) """ try: self.__input = int(txt, 16) self.__inputValid = True except ValueError: self.__inputValid = False if self.__inputValid: self.__formatNumbers(16) else: self.hexEdit.setStyleSheet(self.__badNumberSheet) @pyqtSlot() def on_hexOutButton_clicked(self): """ Private slot to send a hexadecimal number. """ self.insertNumber.emit(self.hexEdit.text())