Files
HackRF-Treasure-Chest/Software/Universal Radio Hacker/src/urh/controller/SimulatorTabController.py
RocketGod e7667c1d93 Add urh
2022-09-22 13:46:47 -07:00

584 lines
27 KiB
Python

import xml.etree.ElementTree as ET
import numpy
from PyQt5.QtCore import pyqtSlot, Qt, QDir, QStringListModel, pyqtSignal
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QWidget, QFileDialog, QCompleter, QMessageBox, QFrame, \
QHBoxLayout, QToolButton, QDialog
from urh.controller.CompareFrameController import CompareFrameController
from urh.controller.GeneratorTabController import GeneratorTabController
from urh.controller.dialogs.ModulatorDialog import ModulatorDialog
from urh.controller.dialogs.ProtocolLabelDialog import ProtocolLabelDialog
from urh.controller.dialogs.SimulatorDialog import SimulatorDialog
from urh.controller.widgets.ChecksumWidget import ChecksumWidget
from urh.models.ParticipantTableModel import ParticipantTableModel
from urh.models.SimulatorMessageFieldModel import SimulatorMessageFieldModel
from urh.models.SimulatorMessageTableModel import SimulatorMessageTableModel
from urh.models.SimulatorParticipantListModel import SimulatorParticipantListModel
from urh.signalprocessing.Participant import Participant
from urh.signalprocessing.ProtocoLabel import ProtocolLabel
from urh.simulator.SimulatorConfiguration import SimulatorConfiguration
from urh.simulator.SimulatorCounterAction import SimulatorCounterAction
from urh.simulator.SimulatorExpressionParser import SimulatorExpressionParser
from urh.simulator.SimulatorGotoAction import SimulatorGotoAction
from urh.simulator.SimulatorItem import SimulatorItem
from urh.simulator.SimulatorMessage import SimulatorMessage
from urh.simulator.SimulatorProtocolLabel import SimulatorProtocolLabel
from urh.simulator.SimulatorRule import SimulatorRuleCondition, ConditionType
from urh.simulator.SimulatorSleepAction import SimulatorSleepAction
from urh.simulator.SimulatorTriggerCommandAction import SimulatorTriggerCommandAction
from urh.ui.RuleExpressionValidator import RuleExpressionValidator
from urh.ui.SimulatorScene import SimulatorScene
from urh.ui.delegates.ComboBoxDelegate import ComboBoxDelegate
from urh.ui.delegates.ProtocolValueDelegate import ProtocolValueDelegate
from urh.ui.ui_simulator import Ui_SimulatorTab
from urh.util import util, FileOperator
from urh.util.Errors import Errors
from urh.util.Logger import logger
from urh.util.ProjectManager import ProjectManager
class SimulatorTabController(QWidget):
open_in_analysis_requested = pyqtSignal(str)
rx_file_saved = pyqtSignal(str)
def __init__(self, compare_frame_controller: CompareFrameController,
generator_tab_controller: GeneratorTabController,
project_manager: ProjectManager, parent):
super().__init__(parent)
self.project_manager = project_manager
self.compare_frame_controller = compare_frame_controller
self.generator_tab_controller = generator_tab_controller
self.proto_analyzer = compare_frame_controller.proto_analyzer
self.simulator_config = SimulatorConfiguration(self.project_manager)
self.sim_expression_parser = SimulatorExpressionParser(self.simulator_config)
SimulatorItem.simulator_config = self.simulator_config
SimulatorItem.expression_parser = self.sim_expression_parser
self.ui = Ui_SimulatorTab()
self.ui.setupUi(self)
util.set_splitter_stylesheet(self.ui.splitter)
util.set_splitter_stylesheet(self.ui.splitterLeftRight)
self.ui.splitter.setSizes([int(self.width() / 0.7), int(self.width() / 0.3)])
self.ui.treeProtocols.setHeaderHidden(True)
self.tree_model = self.generator_tab_controller.tree_model
self.ui.treeProtocols.setModel(self.tree_model)
self.participant_table_model = ParticipantTableModel(project_manager.participants)
self.ui.tableViewParticipants.setModel(self.participant_table_model)
self.participant_table_model.update()
self.simulator_message_field_model = SimulatorMessageFieldModel(self)
self.ui.tblViewFieldValues.setModel(self.simulator_message_field_model)
self.ui.tblViewFieldValues.setItemDelegateForColumn(1, ComboBoxDelegate(ProtocolLabel.DISPLAY_FORMATS,
parent=self.ui.tblViewFieldValues))
self.ui.tblViewFieldValues.setItemDelegateForColumn(2, ComboBoxDelegate(SimulatorProtocolLabel.VALUE_TYPES,
parent=self.ui.tblViewFieldValues))
self.ui.tblViewFieldValues.setItemDelegateForColumn(3, ProtocolValueDelegate(controller=self,
parent=self.ui.tblViewFieldValues))
self.project_manager.reload_field_types()
self.update_field_name_column()
self.simulator_message_table_model = SimulatorMessageTableModel(self.project_manager, self)
self.ui.tblViewMessage.setModel(self.simulator_message_table_model)
self.ui.ruleCondLineEdit.setValidator(RuleExpressionValidator(self.sim_expression_parser, is_formula=False))
self.completer_model = QStringListModel([])
self.ui.ruleCondLineEdit.setCompleter(QCompleter(self.completer_model, self.ui.ruleCondLineEdit))
self.ui.ruleCondLineEdit.setToolTip(self.sim_expression_parser.rule_condition_help)
self.simulator_scene = SimulatorScene(mode=0, simulator_config=self.simulator_config)
self.simulator_scene.tree_root_item = compare_frame_controller.proto_tree_model.rootItem
self.ui.gvSimulator.setScene(self.simulator_scene)
self.ui.gvSimulator.setAlignment(Qt.AlignLeft | Qt.AlignTop)
self.ui.gvSimulator.proto_analyzer = compare_frame_controller.proto_analyzer
self.__active_item = None
self.ui.listViewSimulate.setModel(SimulatorParticipantListModel(self.simulator_config))
self.ui.spinBoxNRepeat.setValue(self.project_manager.simulator_num_repeat)
self.ui.spinBoxTimeout.setValue(self.project_manager.simulator_timeout_ms)
self.ui.spinBoxRetries.setValue(self.project_manager.simulator_retries)
self.ui.comboBoxError.setCurrentIndex(self.project_manager.simulator_error_handling_index)
# place save/load button at corner of tab widget
frame = QFrame(parent=self)
frame.setLayout(QHBoxLayout())
frame.setFrameStyle(frame.NoFrame)
self.ui.btnSave = QToolButton(self.ui.tab)
self.ui.btnSave.setIcon(QIcon.fromTheme("document-save"))
frame.layout().addWidget(self.ui.btnSave)
self.ui.btnLoad = QToolButton(self.ui.tab)
self.ui.btnLoad.setIcon(QIcon.fromTheme("document-open"))
frame.layout().addWidget(self.ui.btnLoad)
frame.layout().setContentsMargins(0, 0, 0, 0)
self.ui.tabWidget.setCornerWidget(frame)
self.ui.splitterLeftRight.setSizes([int(0.2 * self.width()), int(0.8 * self.width())])
self.create_connects()
def refresh_field_types_for_labels(self):
for msg in self.simulator_config.get_all_messages():
for lbl in (lbl for lbl in msg.message_type if lbl.field_type is not None):
msg.message_type.change_field_type_of_label(lbl, self.field_types_by_caption.get(lbl.field_type.caption,
None))
self.update_field_name_column()
self.update_ui()
@property
def field_types(self):
return self.project_manager.field_types
@property
def field_types_by_caption(self):
return self.project_manager.field_types_by_caption
def update_field_name_column(self):
field_types = [ft.caption for ft in self.field_types]
self.ui.tblViewFieldValues.setItemDelegateForColumn(0, ComboBoxDelegate(field_types, is_editable=True,
return_index=False,
parent=self.ui.tblViewFieldValues))
def create_connects(self):
self.ui.btnChooseCommand.clicked.connect(self.on_btn_choose_command_clicked)
self.ui.lineEditTriggerCommand.textChanged.connect(self.on_line_edit_trigger_command_text_changed)
self.ui.checkBoxPassTranscriptSTDIN.clicked.connect(self.on_check_box_pass_transcript_STDIN_clicked)
self.ui.doubleSpinBoxSleep.editingFinished.connect(self.on_spinbox_sleep_editing_finished)
self.ui.ruleCondLineEdit.textChanged.connect(self.on_rule_cond_line_edit_text_changed)
self.ui.btnStartSim.clicked.connect(self.on_btn_simulate_clicked)
self.ui.goto_combobox.currentIndexChanged.connect(self.on_goto_combobox_index_changed)
self.ui.spinBoxRepeat.valueChanged.connect(self.on_repeat_value_changed)
self.ui.cbViewType.currentIndexChanged.connect(self.on_view_type_changed)
self.ui.tblViewMessage.create_label_triggered.connect(self.create_simulator_label)
self.ui.tblViewMessage.open_modulator_dialog_clicked.connect(self.open_modulator_dialog)
self.ui.tblViewMessage.selectionModel().selectionChanged.connect(self.on_table_selection_changed)
self.ui.tabWidget.currentChanged.connect(self.on_selected_tab_changed)
self.ui.btnSave.clicked.connect(self.on_btn_save_clicked)
self.ui.btnLoad.clicked.connect(self.on_btn_load_clicked)
self.ui.listViewSimulate.model().participant_simulate_changed.connect(self.on_participant_simulate_changed)
self.ui.btnAddParticipant.clicked.connect(self.ui.tableViewParticipants.on_add_action_triggered)
self.ui.btnRemoveParticipant.clicked.connect(self.ui.tableViewParticipants.on_remove_action_triggered)
self.ui.btnUp.clicked.connect(self.ui.tableViewParticipants.on_move_up_action_triggered)
self.ui.btnDown.clicked.connect(self.ui.tableViewParticipants.on_move_down_action_triggered)
self.participant_table_model.participant_edited.connect(self.on_participant_edited)
self.tree_model.modelReset.connect(self.refresh_tree)
self.simulator_scene.selectionChanged.connect(self.on_simulator_scene_selection_changed)
self.simulator_scene.files_dropped.connect(self.on_files_dropped)
self.simulator_message_field_model.protocol_label_updated.connect(self.item_updated)
self.ui.gvSimulator.message_updated.connect(self.item_updated)
self.ui.gvSimulator.consolidate_messages_clicked.connect(self.consolidate_messages)
self.simulator_config.items_added.connect(self.refresh_message_table)
self.simulator_config.items_updated.connect(self.refresh_message_table)
self.simulator_config.items_moved.connect(self.refresh_message_table)
self.simulator_config.items_deleted.connect(self.refresh_message_table)
self.simulator_config.participants_changed.connect(self.on_participants_changed)
self.simulator_config.item_dict_updated.connect(self.on_item_dict_updated)
self.simulator_config.active_participants_updated.connect(self.on_active_participants_updated)
self.ui.gvSimulator.message_updated.connect(self.on_message_source_or_destination_updated)
self.ui.spinBoxNRepeat.valueChanged.connect(self.on_spinbox_num_repeat_value_changed)
self.ui.spinBoxTimeout.valueChanged.connect(self.on_spinbox_timeout_value_changed)
self.ui.comboBoxError.currentIndexChanged.connect(self.on_combobox_error_handling_index_changed)
self.ui.spinBoxRetries.valueChanged.connect(self.on_spinbox_retries_value_changed)
self.ui.tblViewFieldValues.item_link_clicked.connect(self.on_table_item_link_clicked)
self.ui.tblViewMessage.edit_label_triggered.connect(self.on_edit_label_triggered)
self.ui.spinBoxCounterStart.editingFinished.connect(self.on_spinbox_counter_start_editing_finished)
self.ui.spinBoxCounterStep.editingFinished.connect(self.on_spinbox_counter_step_editing_finished)
def consolidate_messages(self):
self.simulator_config.consolidate_messages()
def on_repeat_value_changed(self, value):
self.active_item.repeat = value
self.simulator_config.items_updated.emit([self.active_item])
def on_item_dict_updated(self):
self.completer_model.setStringList(self.sim_expression_parser.get_identifiers())
def on_selected_tab_changed(self, index: int):
if index == 0:
if self.active_item is not None:
self.ui.gvSimulator.jump_to_item(self.active_item)
else:
self.update_ui()
else:
self.ui.tblViewMessage.resize_columns()
self.update_vertical_table_header()
def refresh_message_table(self):
self.simulator_message_table_model.protocol.messages[:] = self.simulator_config.get_all_messages()
self.simulator_message_table_model.update()
if isinstance(self.active_item, SimulatorMessage):
self.simulator_message_field_model.update()
self.ui.tblViewMessage.resize_columns()
self.update_ui()
def load_config_from_xml_tag(self, xml_tag, update_before=True):
if xml_tag is None:
return
if update_before:
self.simulator_config.on_project_updated()
self.simulator_config.load_from_xml(xml_tag, self.proto_analyzer.message_types)
self.project_manager.project_updated.emit()
def load_simulator_file(self, filename: str):
try:
tree = ET.parse(filename)
self.load_config_from_xml_tag(tree.getroot(), update_before=False)
except Exception as e:
logger.exception(e)
def save_simulator_file(self, filename: str):
tag = self.simulator_config.save_to_xml(standalone=True)
util.write_xml_to_file(tag, filename)
def close_all(self):
self.simulator_scene.clear_all()
@pyqtSlot(int, int, int)
def create_simulator_label(self, msg_index: int, start: int, end: int):
con = self.simulator_message_table_model.protocol
start, end = con.convert_range(start, end - 1, self.ui.cbViewType.currentIndex(), 0, False, msg_index)
lbl = self.simulator_config.add_label(start=start, end=end, parent_item=con.messages[msg_index])
try:
index = self.simulator_message_field_model.message_type.index(lbl)
self.ui.tblViewFieldValues.edit(self.simulator_message_field_model.createIndex(index, 0))
except ValueError:
pass
@pyqtSlot()
def open_modulator_dialog(self):
selected_message = self.simulator_message_table_model.protocol.messages[self.ui.tblViewMessage.selected_rows[0]]
preselected_index = selected_message.modulator_index
modulator_dialog = ModulatorDialog(self.project_manager.modulators, tree_model=self.tree_model, parent=self)
modulator_dialog.ui.comboBoxCustomModulations.setCurrentIndex(preselected_index)
modulator_dialog.showMaximized()
modulator_dialog.initialize(selected_message.encoded_bits_str[0:16])
modulator_dialog.finished.connect(self.refresh_modulators)
modulator_dialog.finished.connect(self.generator_tab_controller.refresh_pause_list)
@pyqtSlot()
def refresh_modulators(self):
# update Generator tab ...
cBoxModulations = self.generator_tab_controller.ui.cBoxModulations
current_index = cBoxModulations.currentIndex()
cBoxModulations.clear()
for modulator in self.project_manager.modulators:
cBoxModulations.addItem(modulator.name)
cBoxModulations.setCurrentIndex(current_index)
# update Simulator tab ...
index = self.sender().ui.comboBoxCustomModulations.currentIndex()
for row in self.ui.tblViewMessage.selected_rows:
self.simulator_message_table_model.protocol.messages[row].modulator_index = index
def update_goto_combobox(self, active_item: SimulatorGotoAction):
assert isinstance(active_item, SimulatorGotoAction)
goto_combobox = self.ui.goto_combobox
goto_combobox.blockSignals(True)
goto_combobox.clear()
goto_combobox.addItem("Select item ...")
goto_combobox.addItems(active_item.get_valid_goto_targets())
goto_combobox.setCurrentIndex(-1)
goto_combobox.blockSignals(False)
index = goto_combobox.findText(self.active_item.goto_target)
if index == -1:
index = 0
goto_combobox.setCurrentIndex(index)
def update_ui(self):
if self.active_item is not None:
text = self.tr("Detail view for item #") + self.active_item.index()
if isinstance(self.active_item, SimulatorMessage):
text += " (" + self.active_item.message_type.name + ")"
self.ui.spinBoxRepeat.setValue(self.active_item.repeat)
self.ui.lblEncodingDecoding.setText(self.active_item.decoder.name)
self.ui.lblMsgFieldsValues.setText(text)
else:
self.ui.lblMsgFieldsValues.setText(self.tr("Detail view for item"))
def update_vertical_table_header(self):
self.simulator_message_table_model.refresh_vertical_header()
self.ui.tblViewMessage.resize_vertical_header()
@pyqtSlot()
def on_rule_cond_line_edit_text_changed(self):
self.active_item.condition = self.ui.ruleCondLineEdit.text()
self.item_updated(self.active_item)
@pyqtSlot()
def on_view_type_changed(self):
self.simulator_message_table_model.proto_view = self.ui.cbViewType.currentIndex()
self.simulator_message_table_model.update()
self.ui.tblViewMessage.resize_columns()
@pyqtSlot()
def on_goto_combobox_index_changed(self):
if not isinstance(self.active_item, SimulatorGotoAction):
return
self.active_item.goto_target = None if self.ui.goto_combobox.currentIndex() == 0 else self.ui.goto_combobox.currentText()
self.item_updated(self.active_item)
@pyqtSlot()
def on_simulator_scene_selection_changed(self):
selected_items = self.simulator_scene.selectedItems()
self.active_item = selected_items[0].model_item if selected_items else None
self.update_ui()
@pyqtSlot()
def on_table_selection_changed(self):
selection = self.ui.tblViewMessage.selectionModel().selection()
if selection.isEmpty():
self.active_item = None
self.ui.lNumSelectedColumns.setText("0")
else:
max_row = numpy.max([rng.bottom() for rng in selection])
self.active_item = self.simulator_message_table_model.protocol.messages[max_row]
_, _, start, end = self.ui.tblViewMessage.selection_range()
self.ui.lNumSelectedColumns.setText(str(end - start))
self.update_ui()
@property
def active_item(self):
return self.__active_item
@active_item.setter
def active_item(self, value):
self.__active_item = value
if isinstance(self.active_item, SimulatorGotoAction):
self.update_goto_combobox(self.active_item)
self.ui.detail_view_widget.setCurrentIndex(1)
elif isinstance(self.active_item, SimulatorMessage):
self.simulator_message_field_model.update()
self.ui.spinBoxRepeat.setValue(self.active_item.repeat)
self.ui.lblEncodingDecoding.setText(self.active_item.decoder.name)
self.ui.detail_view_widget.setCurrentIndex(2)
elif (isinstance(self.active_item, SimulatorRuleCondition) and
self.active_item.type != ConditionType.ELSE):
self.ui.ruleCondLineEdit.setText(self.active_item.condition)
self.ui.detail_view_widget.setCurrentIndex(3)
elif isinstance(self.active_item, SimulatorTriggerCommandAction):
self.ui.lineEditTriggerCommand.setText(self.active_item.command)
self.ui.checkBoxPassTranscriptSTDIN.setChecked(self.active_item.pass_transcript)
self.ui.detail_view_widget.setCurrentIndex(4)
elif isinstance(self.active_item, SimulatorSleepAction):
self.ui.doubleSpinBoxSleep.setValue(self.active_item.sleep_time)
self.ui.detail_view_widget.setCurrentIndex(5)
elif isinstance(self.active_item, SimulatorCounterAction):
self.ui.spinBoxCounterStart.setValue(self.active_item.start)
self.ui.spinBoxCounterStep.setValue(self.active_item.step)
self.ui.detail_view_widget.setCurrentIndex(6)
else:
self.ui.detail_view_widget.setCurrentIndex(0)
self.update_ui()
@pyqtSlot()
def on_btn_simulate_clicked(self):
if not self.simulator_config.protocol_valid():
QMessageBox.critical(self, self.tr("Invalid protocol configuration"),
self.tr(
"There are some problems with your protocol configuration. Please fix them first."))
return
if not len(self.simulator_config.get_all_messages()):
QMessageBox.critical(self, self.tr("No messages found"), self.tr("Please add at least one message."))
return
num_simulated = len([p for p in self.project_manager.participants if p.simulate])
if num_simulated == 0:
if self.ui.listViewSimulate.model().rowCount() == 0:
QMessageBox.critical(self, self.tr("No active participants"),
self.tr("You have no active participants.<br>"
"Please add a participant in the <i>Participants tab</i> and "
"assign it to at least one message as <i>source</i> or <i>destination.</i>"))
return
else:
QMessageBox.critical(self, self.tr("No participant for simulation selected"),
self.tr("Please check at least one participant from the "
"<i>Simulate these participants</i> list."))
return
try:
self.get_simulator_dialog().exec_()
except Exception as e:
Errors.exception(e)
def get_simulator_dialog(self) -> SimulatorDialog:
protos = [p for proto_list in self.tree_model.protocols.values() for p in proto_list]
signals = [p.signal for p in protos if p.signal is not None]
s = SimulatorDialog(self.simulator_config, self.project_manager.modulators,
self.sim_expression_parser, self.project_manager, signals=signals,
signal_tree_model=self.tree_model, parent=self)
s.rx_parameters_changed.connect(self.project_manager.on_simulator_rx_parameters_changed)
s.sniff_parameters_changed.connect(self.project_manager.on_simulator_sniff_parameters_changed)
s.tx_parameters_changed.connect(self.project_manager.on_simulator_tx_parameters_changed)
s.open_in_analysis_requested.connect(self.open_in_analysis_requested.emit)
s.rx_file_saved.connect(self.rx_file_saved.emit)
return s
@pyqtSlot()
def on_btn_choose_command_clicked(self):
file_name, ok = QFileDialog.getOpenFileName(self, self.tr("Choose program"), QDir.homePath())
if file_name is not None and ok:
self.ui.lineEditTriggerCommand.setText(file_name)
@pyqtSlot()
def on_line_edit_trigger_command_text_changed(self):
self.active_item.command = self.ui.lineEditTriggerCommand.text()
self.item_updated(self.active_item)
@pyqtSlot()
def on_check_box_pass_transcript_STDIN_clicked(self):
self.active_item.pass_transcript = self.ui.checkBoxPassTranscriptSTDIN.isChecked()
self.item_updated(self.active_item)
@pyqtSlot()
def on_spinbox_counter_start_editing_finished(self):
self.active_item.start = self.ui.spinBoxCounterStart.value()
self.item_updated(self.active_item)
@pyqtSlot()
def on_spinbox_counter_step_editing_finished(self):
self.active_item.step = self.ui.spinBoxCounterStep.value()
self.item_updated(self.active_item)
@pyqtSlot()
def on_spinbox_sleep_editing_finished(self):
self.active_item.sleep_time = self.ui.doubleSpinBoxSleep.value()
self.item_updated(self.active_item)
@pyqtSlot()
def on_participants_changed(self):
self.update_vertical_table_header()
self.participant_table_model.update()
self.ui.listViewSimulate.model().update()
def item_updated(self, item: SimulatorItem):
self.simulator_config.items_updated.emit([item])
@pyqtSlot()
def refresh_tree(self):
self.ui.treeProtocols.expandAll()
@pyqtSlot()
def on_btn_save_clicked(self):
filename = FileOperator.ask_save_file_name(initial_name="myprofile.sim.xml", caption="Save simulator profile")
if filename:
self.save_simulator_file(filename)
@pyqtSlot()
def on_btn_load_clicked(self):
dialog = FileOperator.get_open_dialog(False, parent=self, name_filter="simulator")
if dialog.exec_():
self.load_simulator_file(dialog.selectedFiles()[0])
@pyqtSlot()
def on_participant_edited(self):
self.project_manager.project_updated.emit()
@pyqtSlot(int)
def on_spinbox_num_repeat_value_changed(self, value):
self.project_manager.simulator_num_repeat = value
@pyqtSlot(int)
def on_spinbox_timeout_value_changed(self, value):
self.project_manager.simulator_timeout_ms = value
@pyqtSlot(int)
def on_spinbox_retries_value_changed(self, value):
self.project_manager.simulator_retries = value
@pyqtSlot(int)
def on_combobox_error_handling_index_changed(self, index: int):
self.project_manager.simulator_error_handling_index = index
@pyqtSlot()
def on_message_source_or_destination_updated(self):
self.simulator_config.update_active_participants()
@pyqtSlot(int, int)
def on_table_item_link_clicked(self, row: int, column: int):
try:
lbl = self.simulator_message_field_model.message_type[row] # type: SimulatorProtocolLabel
assert lbl.is_checksum_label
assert isinstance(self.active_item, SimulatorMessage)
except (IndexError, AssertionError):
return
d = QDialog(parent=self)
layout = QHBoxLayout()
layout.addWidget(ChecksumWidget(lbl.label, self.active_item, self.ui.cbViewType.currentIndex()))
d.setLayout(layout)
d.show()
@pyqtSlot(Participant)
def on_participant_simulate_changed(self, participant: Participant):
self.simulator_scene.refresh_participant(participant)
@pyqtSlot()
def on_active_participants_updated(self):
self.ui.listViewSimulate.model().update()
@pyqtSlot(int)
def on_edit_label_triggered(self, label_index: int):
view_type = self.ui.cbViewType.currentIndex()
protocol_label_dialog = ProtocolLabelDialog(message=self.ui.tblViewMessage.selected_message,
viewtype=view_type, selected_index=label_index, parent=self)
protocol_label_dialog.finished.connect(self.on_protocol_label_dialog_finished)
protocol_label_dialog.showMaximized()
@pyqtSlot()
def on_protocol_label_dialog_finished(self):
self.simulator_message_field_model.update()
self.simulator_message_table_model.update()
self.update_ui()
@pyqtSlot(list)
def on_files_dropped(self, file_urls: list):
for filename in (file_url.toLocalFile() for file_url in file_urls if file_url.isLocalFile()):
self.load_simulator_file(filename)