from PyQt5.QtCore import QAbstractTableModel, Qt, QModelIndex, pyqtSignal from PyQt5.QtGui import QFont from PyQt5.QtWidgets import qApp from urh import settings from urh.signalprocessing.FieldType import FieldType from urh.signalprocessing.MessageType import MessageType from urh.signalprocessing.ProtocoLabel import ProtocolLabel from urh.simulator.SimulatorProtocolLabel import SimulatorProtocolLabel from urh.util import util class SimulatorMessageFieldModel(QAbstractTableModel): header_labels = ['Name', 'Display format', 'Value type', 'Value'] protocol_label_updated = pyqtSignal(SimulatorProtocolLabel) def __init__(self, controller, parent=None): super().__init__(parent) self.controller = controller # type: SimulatorTabController self.message_type = None # type: MessageType def update(self): self.beginResetModel() self.message_type = self.controller.active_item.message_type self.endResetModel() def columnCount(self, parent: QModelIndex=None, *args, **kwargs): return len(self.header_labels) def rowCount(self, parent: QModelIndex=None, *args, **kwargs): return len(self.message_type) if self.message_type is not None else 0 def headerData(self, section, orientation, role=Qt.DisplayRole): if role == Qt.DisplayRole and orientation == Qt.Horizontal: return self.header_labels[section] elif role == Qt.TextAlignmentRole: return Qt.AlignLeft return super().headerData(section, orientation, role) def data(self, index: QModelIndex, role=Qt.DisplayRole): i, j = index.row(), index.column() lbl = self.message_type[i] # type: SimulatorProtocolLabel if role == Qt.DisplayRole: if j == 0: return lbl.name elif j == 1: return ProtocolLabel.DISPLAY_FORMATS[lbl.display_format_index] elif j == 2: if lbl.is_checksum_label: return "Checksum" else: return lbl.VALUE_TYPES[lbl.value_type_index] elif j == 3: if lbl.value_type_index == 0: message = lbl.parent() try: data = message.plain_bits[lbl.start:lbl.end] except IndexError: return None return util.convert_bits_to_string(data, lbl.display_format_index, pad_zeros=True) elif lbl.value_type_index == 1: return "-" elif lbl.value_type_index == 2: return lbl.formula elif lbl.value_type_index == 3: return lbl.external_program elif lbl.value_type_index == 4: return "Range (Decimal): " + str(lbl.random_min) + " - " + str(lbl.random_max) elif role == Qt.EditRole: if j == 0: return lbl.name elif j == 1: return lbl.display_format_index elif j == 2: return lbl.value_type_index elif j == 3: if lbl.value_type_index == 2: return lbl.formula elif lbl.value_type_index == 3: return lbl.external_program elif lbl.value_type_index == 4: return [lbl.random_min, lbl.random_max] elif role == Qt.FontRole: if j == 0: font = QFont() font.setItalic(lbl.field_type is None) return font elif j == 2 and self.link_index(index): font = QFont() font.setUnderline(True) return font elif role == Qt.BackgroundColorRole: if j == 0: return settings.LABEL_COLORS[lbl.color_index] elif j == 3: if (lbl.value_type_index == 2 and not self.controller.sim_expression_parser.validate_expression(lbl.formula)[0]): return settings.ERROR_BG_COLOR elif role == Qt.TextColorRole: if self.link_index(index): return qApp.palette().link().color() def link_index(self, index: QModelIndex): try: lbl = self.message_type[index.row()] # type: SimulatorProtocolLabel if index.column() == 2 and lbl.is_checksum_label: return True except: return False return False def setData(self, index: QModelIndex, value, role=None): if role == Qt.EditRole: i, j = index.row(), index.column() label = self.message_type[i] # type: SimulatorProtocolLabel if j == 0: label.name = value ft = self.controller.field_types_by_caption.get(value, FieldType("Custom", FieldType.Function.CUSTOM)) label.field_type = ft elif j == 1: label.display_format_index = value elif j == 2: label.value_type_index = value elif j == 3: if label.value_type_index == 0: message = label.parent() try: bits = util.convert_string_to_bits(value, label.display_format_index, target_num_bits=label.end-label.start) message.plain_bits[label.start:label.end] = bits except ValueError: pass elif label.value_type_index == 2: label.formula = value elif label.value_type_index == 3: label.external_program = value elif label.value_type_index == 4: label.random_min = value[0] label.random_max = value[1] self.dataChanged.emit(self.index(i, 0), self.index(i, self.columnCount())) self.protocol_label_updated.emit(label) return True def flags(self, index: QModelIndex): row, col = index.row(), index.column() label = self.message_type[row] # type: SimulatorProtocolLabel if col == 2 and label.is_checksum_label: return Qt.ItemIsSelectable flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable if not(col == 3 and label.value_type_index == 1): flags |= Qt.ItemIsEditable return flags def remove_label_at(self, index: int): try: label = self.message_type[index] self.controller.simulator_config.delete_items([label]) except IndexError: pass def set_value_type_index(self, rows: list, value_type_index: int): for row in rows: label = self.message_type[row] if not label.is_checksum_label: label.value_type_index = value_type_index self.protocol_label_updated.emit(label) self.update()