Пример #1
0
    def __init__(self):
        super().__init__()

        self.ui = MainForm()
        self.ui.setupUi(self)

        try:
            self.settings = settings.get_ini_settings(
                os.path.join(self.get_application_path(), "settings.ini"))
            ini_ok = True
        except BadIniException:
            ini_ok = False
            QtWidgets.QMessageBox.critical(self, Text.get("err"),
                                           Text.get("ini_err"))
        if ini_ok:
            self.settings.restore_qwidget_state(self)
            self.settings.restore_qwidget_state(self.ui.mw_splitter_1)
            self.settings.restore_qwidget_state(self.ui.measures_table)

            self.ui.download_progress_bar.setHidden(True)

            if ENGLISH_VERSION:
                self.ui.russian_language_action.setVisible(False)
                self.settings.language = Text.Lang.EN

            self.translator = QtCore.QTranslator(
                QtWidgets.QApplication.instance())
            self.install_translator(self.settings.language)

            if self.settings.language == Text.Lang.EN:
                self.ui.english_language_action.setChecked(True)
            else:
                self.ui.russian_language_action.setChecked(True)

            self.set_up_logger()

            self.ui.measures_table.setItemDelegate(
                TransparentPainterForView(self.ui.measures_table, "#d4d4ff"))
            self.ui.download_path_edit.setText(self.settings.save_folder_path)

            self.ui.ip_combobox.setEditText(self.settings.ip)
            self.ui.download_path_edit.setText(self.settings.path)
            self.ui.name_template_edit.setText(self.settings.name_template)
            self.ui.save_folder_edit.setText(self.settings.save_folder)

            self.db = UpmsDatabase(
                os.path.join(self.get_application_path(), "database.db"))
            self.measures_table_model = None
            self.proxy = None
            self.update_model()

            self.bcast_sockets = {}
            self.get_broadcast_ips()

            self.show()
            self.connect_all()

            self.ui.get_ip_button.click()
        else:
            self.close()
Пример #2
0
    def __init__(self):
        super().__init__()

        self.ui = MainForm()
        self.ui.setupUi(self)

        self.active_window = None

        try:
            self.settings = Settings(self)
            ini_ok = True
        except BadIniException:
            ini_ok = False
            QtWidgets.QMessageBox.critical(
                self, "Ошибка", 'Файл конфигурации поврежден. Пожалуйста, '
                'удалите файл "settings.ini" и запустите программу заново')
        if ini_ok:
            self.db_name = "measures.db"
            self.db_connection = MeasuresDB.create_db(self.db_name)
            self.show_start_window()
            self.show()

            self.clb_signal_off_timer = QtCore.QTimer()
            # noinspection PyTypeChecker
            self.clb_signal_off_timer.timeout.connect(self.close)
            self.SIGNAL_OFF_TIME_MS = 200

            self.clb_driver = clb_dll.set_up_driver(clb_dll.debug_dll_path)
            self.usb_driver = clb_dll.UsbDrv(self.clb_driver)
            self.usb_state = clb_dll.UsbDrv.UsbState.DISABLED
            self.calibrator = clb_dll.ClbDrv(self.clb_driver)
            self.clb_state = clb.State.DISCONNECTED

            self.usb_check_timer = QtCore.QTimer(self)
            self.usb_check_timer.timeout.connect(self.usb_tick)
            self.usb_check_timer.start(10)

            self.fast_config = None

            self.ui.enter_settings_action.triggered.connect(self.open_settings)

        else:
            self.close()
Пример #3
0
    def __init__(self):
        super().__init__()

        self.ui = MainForm()
        self.ui.setupUi(self)

        try:
            self.settings = settings.get_clb_autocalibration_settings()
            ini_ok = True
        except BadIniException:
            ini_ok = False
            QtWidgets.QMessageBox.critical(
                self, "Ошибка", 'Файл конфигурации поврежден. Пожалуйста, '
                'удалите файл "settings.ini" и запустите программу заново')
        if ini_ok:
            self.settings.restore_qwidget_state(self)
            self.settings.restore_qwidget_state(self.ui.mainwindow_splitter)
            self.settings.restore_qwidget_state(self.ui.mainwindow_splitter_2)
            self.settings.restore_qwidget_state(self.ui.measures_table)

            self.ui.measures_table.setItemDelegate(
                TransparentPainterForWidget(self.ui.measures_table, "#d4d4ff"))

            self.ui.progress_bar_widget.setHidden(True)

            for i in range(CellData.GetDataType.COUNT):
                self.ui.displayed_data_type_combobox.addItem(
                    MainWindow.displayed_data_to_text[i])

            self.set_up_logger()

            self.ftdi_control = FtdiControl()

            self.clb_driver = clb_dll.clb_dll

            modbus_registers_count = 700
            self.usb_driver = clb_dll.UsbDrv(self.clb_driver,
                                             modbus_registers_count * 2)
            self.usb_state = clb_dll.UsbDrv.UsbState.DISABLED
            self.calibrator = clb_dll.ClbDrv(self.clb_driver)
            self.clb_state = clb.State.DISCONNECTED

            self.netvars = NetworkVariables(f"./{clb.CLB_CONFIG_NAME}",
                                            self.calibrator,
                                            a_variables_read_delay=0)

            self.clb_signal_off_timer = QtCore.QTimer()
            # noinspection PyTypeChecker
            self.clb_signal_off_timer.timeout.connect(self.close)
            self.SIGNAL_OFF_TIME_MS = 200
            self.ignore_save = False

            self.current_configuration_path = ""

            self.measure_progress_bar_value = 0

            self.tstlan_dialog = None
            self.graphs_dialog = None

            self.open_correction_tables = False

            self.show()

            self.measure_manager = MeasureManager(self.ui.measures_table,
                                                  self.ui.measure_data_view,
                                                  self.settings, self)
            self.open_configuration_by_name(
                self.settings.last_configuration_path)

            self.measure_conductor = MeasureConductor(self.calibrator,
                                                      self.netvars,
                                                      self.measure_manager,
                                                      self.settings)
            self.measure_conductor.all_measures_done.connect(self.measure_done)
            self.measure_conductor.single_measure_started.connect(
                self.single_measure_started)
            self.measure_conductor.single_measure_done.connect(
                self.single_measure_done)
            self.measure_conductor.verify_flash_done.connect(
                self.verify_flash_done)

            self.connect_all()

            self.tick_timer = QtCore.QTimer(self)
            self.tick_timer.timeout.connect(self.tick)
            self.tick_timer.start(10)

        else:
            self.close()
Пример #4
0
class MainWindow(QtWidgets.QMainWindow):
    clb_list_changed = QtCore.pyqtSignal([list])
    usb_status_changed = QtCore.pyqtSignal(clb.State)
    signal_enable_changed = QtCore.pyqtSignal(bool)

    class CloseConfigOptions(IntEnum):
        SAVE = 0
        DONT_SAVE = 1
        CANCEL = 2

    displayed_data_to_text = {
        CellData.GetDataType.MEASURED: "Измерено",
        CellData.GetDataType.DEVIATION: "Отклонение, %",
        CellData.GetDataType.DELTA_2: "Полудельта, %",
        CellData.GetDataType.SKO_PERCENTS: "СКО, %",
        CellData.GetDataType.STUDENT_95: "Доверительный интервал 0.95, %",
        CellData.GetDataType.STUDENT_99: "Доверительный интервал 0.99, %",
        CellData.GetDataType.STUDENT_999: "Доверительный интервал 0.999, %",
        # CellData.GetDataType.MEASURE_DATE: "Дата измерения",
    }

    def __init__(self):
        super().__init__()

        self.ui = MainForm()
        self.ui.setupUi(self)

        try:
            self.settings = settings.get_clb_autocalibration_settings()
            ini_ok = True
        except BadIniException:
            ini_ok = False
            QtWidgets.QMessageBox.critical(
                self, "Ошибка", 'Файл конфигурации поврежден. Пожалуйста, '
                'удалите файл "settings.ini" и запустите программу заново')
        if ini_ok:
            self.settings.restore_qwidget_state(self)
            self.settings.restore_qwidget_state(self.ui.mainwindow_splitter)
            self.settings.restore_qwidget_state(self.ui.mainwindow_splitter_2)
            self.settings.restore_qwidget_state(self.ui.measures_table)

            self.ui.measures_table.setItemDelegate(
                TransparentPainterForWidget(self.ui.measures_table, "#d4d4ff"))

            self.ui.progress_bar_widget.setHidden(True)

            for i in range(CellData.GetDataType.COUNT):
                self.ui.displayed_data_type_combobox.addItem(
                    MainWindow.displayed_data_to_text[i])

            self.set_up_logger()

            self.ftdi_control = FtdiControl()

            self.clb_driver = clb_dll.clb_dll

            modbus_registers_count = 700
            self.usb_driver = clb_dll.UsbDrv(self.clb_driver,
                                             modbus_registers_count * 2)
            self.usb_state = clb_dll.UsbDrv.UsbState.DISABLED
            self.calibrator = clb_dll.ClbDrv(self.clb_driver)
            self.clb_state = clb.State.DISCONNECTED

            self.netvars = NetworkVariables(f"./{clb.CLB_CONFIG_NAME}",
                                            self.calibrator,
                                            a_variables_read_delay=0)

            self.clb_signal_off_timer = QtCore.QTimer()
            # noinspection PyTypeChecker
            self.clb_signal_off_timer.timeout.connect(self.close)
            self.SIGNAL_OFF_TIME_MS = 200
            self.ignore_save = False

            self.current_configuration_path = ""

            self.measure_progress_bar_value = 0

            self.tstlan_dialog = None
            self.graphs_dialog = None

            self.open_correction_tables = False

            self.show()

            self.measure_manager = MeasureManager(self.ui.measures_table,
                                                  self.ui.measure_data_view,
                                                  self.settings, self)
            self.open_configuration_by_name(
                self.settings.last_configuration_path)

            self.measure_conductor = MeasureConductor(self.calibrator,
                                                      self.netvars,
                                                      self.measure_manager,
                                                      self.settings)
            self.measure_conductor.all_measures_done.connect(self.measure_done)
            self.measure_conductor.single_measure_started.connect(
                self.single_measure_started)
            self.measure_conductor.single_measure_done.connect(
                self.single_measure_done)
            self.measure_conductor.verify_flash_done.connect(
                self.verify_flash_done)

            self.connect_all()

            self.tick_timer = QtCore.QTimer(self)
            self.tick_timer.timeout.connect(self.tick)
            self.tick_timer.start(10)

        else:
            self.close()

    def connect_all(self):
        self.ui.lock_action.triggered.connect(self.lock_cell_button_clicked)
        self.ui.unlock_action.triggered.connect(
            self.unlock_cell_button_clicked)
        self.ui.lock_all_action.triggered.connect(
            self.lock_all_cells_button_clicked)
        self.ui.unlock_all_action.triggered.connect(
            self.unlock_all_cells_button_clicked)
        self.ui.show_equal_action.toggled.connect(
            self.show_equal_cell_configs_button_toggled)

        self.ui.switch_to_active_cell_action.setChecked(
            self.settings.switch_to_active_cell)
        self.ui.switch_to_active_cell_action.triggered.connect(
            self.switch_to_active_cell_action_toggled)

        self.ui.show_scheme_in_cell_action.setChecked(
            self.settings.show_scheme_in_cell)
        self.ui.show_scheme_in_cell_action.triggered.connect(
            self.show_scheme_in_cell_toggled)
        self.show_scheme_in_cell_toggled(self.settings.show_scheme_in_cell)

        self.ui.add_row_button.clicked.connect(self.add_row_button_clicked)
        self.ui.remove_row_button.clicked.connect(
            self.remove_row_button_clicked)
        self.ui.add_column_button.clicked.connect(
            self.add_column_button_clicked)
        self.ui.remove_column_button.clicked.connect(
            self.remove_column_button_clicked)
        self.ui.clear_table_button.clicked.connect(
            self.clear_table_button_clicked)

        self.ui.start_all_action.triggered.connect(
            self.start_all_measures_button_clicked)
        self.ui.continue_all_action.triggered.connect(
            self.continue_all_measures_button_clicked)
        self.ui.start_current_measure_button.clicked.connect(
            self.start_current_measure_button_clicked)
        self.ui.continue_current_measure_button.clicked.connect(
            self.continue_current_measure_button_clicked)
        self.ui.stop_all_action.triggered.connect(
            self.stop_measure_button_clicked)

        self.ui.flash_all_action.triggered.connect(
            self.flash_all_button_clicked)
        self.ui.verify_all_action.triggered.connect(
            self.verify_all_button_clicked)
        self.ui.read_correction_tables_action.triggered.connect(
            self.read_correction_tables_button_clicked)
        self.ui.stop_flash_verify_action.triggered.connect(
            self.stop_flash_verify_button_clicked)
        self.ui.get_correction_tables_from_file_action.triggered.connect(
            self.open_correction_tables_from_file)

        self.ui.measure_data_view.clicked.connect(
            self.measure_data_cell_clicked)
        self.ui.measure_data_view.customContextMenuRequested.connect(
            self.show_data_table_context_menu)

        self.ui.measures_table.customContextMenuRequested.connect(
            self.show_measures_table_context_menu)

        self.ui.enter_settings_action.triggered.connect(self.open_settings)
        self.ui.open_tstlan_action.triggered.connect(self.open_tstlan)
        self.ui.graphs_action.triggered.connect(self.open_graphs)
        self.ui.save_action.triggered.connect(self.save_configuration)
        self.ui.save_as_action.triggered.connect(self.save_configuration_as)
        self.ui.save_current_measure_button.clicked.connect(
            self.save_current_configuration)
        self.ui.open_cell_config_button.clicked.connect(
            self.open_cell_configuration)
        self.ui.open_action.triggered.connect(self.open_configuration)
        self.ui.new_configuration_action.triggered.connect(
            self.create_new_configuration)
        self.ui.clb_list_combobox.currentTextChanged.connect(
            self.connect_to_clb)
        self.ui.add_measure_button.clicked.connect(
            self.add_measure_button_clicked)
        self.ui.delete_measure_button.clicked.connect(
            self.remove_measure_button_clicked)
        self.ui.rename_measure_button.clicked.connect(
            self.rename_measure_button_clicked)
        self.ui.open_shared_measure_parameters_button.clicked.connect(
            self.open_shared_measure_parameters)
        self.ui.update_measure_status_button.clicked.connect(
            self.update_measure_status_button_clicked)

        self.ui.enable_all_button.clicked.connect(
            self.enable_all_button_clicked)

        self.ui.copy_cell_config_action.triggered.connect(
            self.copy_cell_config)
        self.ui.measure_data_view.addAction(self.ui.copy_cell_config_action)
        self.ui.paste_cell_config_action.triggered.connect(
            self.paste_cell_config)
        self.ui.measure_data_view.addAction(self.ui.paste_cell_config_action)

        self.ui.copy_cell_value_action.triggered.connect(self.copy_cell_value)
        self.ui.measure_data_view.addAction(self.ui.copy_cell_value_action)
        self.ui.paste_cell_value_action.triggered.connect(
            self.paste_cell_value)
        self.ui.measure_data_view.addAction(self.ui.paste_cell_value_action)

        self.ui.show_cell_graph_action.triggered.connect(self.open_cell_graph)
        self.ui.measure_data_view.addAction(self.ui.show_cell_graph_action)

        self.ui.flash_current_measure_action.triggered.connect(
            self.flash_table)
        self.ui.measure_data_view.addAction(
            self.ui.flash_current_measure_action)
        self.ui.verify_current_measure_action.triggered.connect(
            self.verify_table)
        self.ui.measure_data_view.addAction(
            self.ui.verify_current_measure_action)
        self.ui.verify_diapason_of_cell_action.triggered.connect(
            self.verify_diapason_of_cell)
        self.ui.measure_data_view.addAction(
            self.ui.verify_diapason_of_cell_action)
        self.ui.flash_diapason_of_cell_action.triggered.connect(
            self.flash_diapason_of_cell)
        self.ui.measure_data_view.addAction(
            self.ui.flash_diapason_of_cell_action)

        self.ui.meter_combobox.currentIndexChanged.connect(self.set_meter)
        self.ui.meter_settings_button.clicked.connect(self.open_meter_settings)

        self.ui.scheme_combobox.setCurrentIndex(self.settings.scheme_type)
        self.ui.scheme_combobox.currentIndexChanged.connect(
            self.set_scheme_type)
        self.set_scheme_type(self.ui.scheme_combobox.currentIndex())

        self.ui.displayed_data_type_combobox.currentIndexChanged.connect(
            self.set_displayed_data)

        self.ui.calculate_divider_coefficients.triggered.connect(
            self.calculate_divider_coefficients_button_clicked)
        self.ui.open_about_action.triggered.connect(self.open_about)

    def set_up_logger(self):
        log = qt_utils.QTextEditLogger(self.ui.log_text_edit)
        log.setFormatter(
            logging.Formatter('%(asctime)s - %(message)s', datefmt='%H:%M:%S'))

        file_log = RotatingFileHandler("autocalibration.log",
                                       maxBytes=30 * 1024 * 1024,
                                       backupCount=3,
                                       encoding='utf8')
        file_log.setLevel(logging.DEBUG)
        file_log.setFormatter(
            logging.Formatter('%(asctime)s - %(levelname)s - %(message)s',
                              datefmt='%H:%M:%S'))

        logging.getLogger().addHandler(file_log)
        logging.getLogger().addHandler(log)
        logging.getLogger().setLevel(logging.DEBUG)

    def lock_interface(self, a_lock: bool):
        self.ui.new_configuration_action.setDisabled(a_lock)
        self.ui.open_action.setDisabled(a_lock)
        self.ui.save_action.setDisabled(a_lock)
        self.ui.save_as_action.setDisabled(a_lock)

        self.ui.start_all_action.setDisabled(a_lock)
        self.ui.continue_all_action.setDisabled(a_lock)

        self.ui.flash_all_action.setDisabled(a_lock)
        self.ui.verify_all_action.setDisabled(a_lock)
        self.ui.read_correction_tables_action.setDisabled(a_lock)
        self.ui.stop_flash_verify_action.setDisabled(a_lock)

        self.ui.lock_action.setDisabled(a_lock)
        self.ui.unlock_action.setDisabled(a_lock)
        self.ui.lock_all_action.setDisabled(a_lock)
        self.ui.unlock_all_action.setDisabled(a_lock)

        self.ui.save_current_measure_button.setDisabled(a_lock)

        self.ui.start_current_measure_button.setDisabled(a_lock)
        self.ui.continue_current_measure_button.setDisabled(a_lock)

        self.ui.add_row_button.setDisabled(a_lock)
        self.ui.remove_row_button.setDisabled(a_lock)
        self.ui.add_column_button.setDisabled(a_lock)
        self.ui.remove_column_button.setDisabled(a_lock)
        self.ui.clear_table_button.setDisabled(a_lock)

        self.ui.clb_list_combobox.setDisabled(a_lock)
        self.ui.meter_combobox.setDisabled(a_lock)
        self.ui.scheme_combobox.setDisabled(a_lock)

        self.ui.add_measure_button.setDisabled(a_lock)
        self.ui.delete_measure_button.setDisabled(a_lock)
        self.ui.rename_measure_button.setDisabled(a_lock)
        self.ui.update_measure_status_button.setDisabled(a_lock)
        self.ui.enable_all_button.setDisabled(a_lock)

        self.ui.paste_cell_value_action.setDisabled(a_lock)
        self.ui.paste_cell_config_action.setDisabled(a_lock)
        self.ui.flash_current_measure_action.setDisabled(a_lock)
        self.ui.verify_current_measure_action.setDisabled(a_lock)
        self.ui.flash_diapason_of_cell_action.setDisabled(a_lock)
        self.ui.verify_diapason_of_cell_action.setDisabled(a_lock)

        self.ui.progress_bar_widget.setHidden(not a_lock)

        self.measure_manager.lock_interface(a_lock)

    def gui_tick(self):
        self.progress_bars_handling()

        correction_enabled = not self.netvars.ui_correct_off.get()
        correction_enabled_ui = self.ui.correction_action.isChecked()
        if not correction_enabled == correction_enabled_ui:
            self.ui.correction_action.setChecked(correction_enabled)

    def tick(self):
        self.measure_conductor.tick()
        self.usb_driver.tick()
        self.gui_tick()

        if self.usb_driver.is_dev_list_changed():
            self.ui.clb_list_combobox.clear()
            for clb_name in self.usb_driver.get_dev_list():
                self.ui.clb_list_combobox.addItem(clb_name)

        if self.usb_driver.is_status_changed():
            self.usb_state = self.usb_driver.get_status()

        current_state = clb.State.DISCONNECTED
        if self.usb_state == clb_dll.UsbDrv.UsbState.CONNECTED:
            if self.calibrator.signal_enable_changed():
                self.signal_enable_changed.emit(self.calibrator.signal_enable)

            if not self.calibrator.signal_enable:
                current_state = clb.State.STOPPED
            elif not self.calibrator.is_signal_ready():
                current_state = clb.State.WAITING_SIGNAL
            else:
                current_state = clb.State.READY

        if self.clb_state != current_state:
            self.clb_state = current_state
            self.calibrator.state = current_state
            self.usb_status_changed.emit(self.clb_state)

    def connect_to_clb(self, a_clb_name):
        self.calibrator.connect(a_clb_name)

    def count_measure_length(self,
                             a_iteration_type: MeasureManager.IterationType):
        measure_iterator = self.measure_manager.get_measure_iterator(
            a_iteration_type)
        seconds_count = 0
        if measure_iterator is not None:
            cell_position = measure_iterator.get()
            while cell_position is not None:
                cell_config = self.measure_manager.get_cell_config(
                    *cell_position)
                seconds_count += cell_config.measure_delay
                seconds_count += cell_config.measure_time

                measure_iterator.next()
                cell_position = measure_iterator.get()

        return seconds_count

    def set_up_progress_bars_for_measure(self, a_measures_total_length):
        self.ui.measure_progress_bar.setMaximum(a_measures_total_length)

        self.ui.measure_progress_bar.setFormat("%v с. / %m с. (%p%)")
        self.ui.curent_cell_progress_bar.setFormat("%v с. / %m с. (%p%)")

    def start_measure(self, a_iteration_type: MeasureManager.IterationType):
        measure_iterator = self.measure_manager.get_measure_iterator(
            a_iteration_type)
        if measure_iterator is not None:
            # Это происходит, когда нет выделенных ячеек
            if measure_iterator.get() is not None:
                if self.save_configuration():
                    self.lock_interface(True)
                    self.set_up_progress_bars_for_measure(
                        self.count_measure_length(a_iteration_type))

                    if a_iteration_type in (
                            MeasureManager.IterationType.START_ALL,
                            MeasureManager.IterationType.CONTINUE_ALL):
                        auto_flash_to_calibrator = True
                    else:
                        auto_flash_to_calibrator = False

                    self.measure_conductor.start(measure_iterator,
                                                 auto_flash_to_calibrator)

    def progress_bars_handling(self):
        if self.measure_conductor.is_started():
            time_passed = self.measure_conductor.get_current_cell_time_passed()
            self.ui.curent_cell_progress_bar.setValue(time_passed)
            self.ui.measure_progress_bar.setValue(
                self.measure_progress_bar_value + time_passed)
        elif self.measure_conductor.is_correction_flash_verify_started():
            current, full = self.measure_conductor.get_flash_progress()
            self.ui.curent_cell_progress_bar.setValue(current)
            self.ui.measure_progress_bar.setValue(full)

    def single_measure_started(self):
        self.ui.curent_cell_progress_bar.setMaximum(
            self.measure_conductor.get_current_cell_time_duration())

    def single_measure_done(self):
        # "Переливаем" прогресс маленького прогресс бара в большой
        self.measure_progress_bar_value += self.ui.curent_cell_progress_bar.maximum(
        )
        self.ui.curent_cell_progress_bar.setValue(0)
        if not self.save_current_configuration():
            logging.warning(
                "Не удалось сохранить результат после завершения измерения ячейки"
            )

    def measure_done(self):
        self.ui.curent_cell_progress_bar.setValue(0)
        self.ui.curent_cell_progress_bar.resetFormat()
        self.ui.measure_progress_bar.setValue(0)
        self.ui.measure_progress_bar.resetFormat()
        self.measure_progress_bar_value = 0
        self.lock_interface(False)

    def start_all_measures_button_clicked(self, _):
        self.start_measure(MeasureManager.IterationType.START_ALL)

    def continue_all_measures_button_clicked(self, _):
        self.start_measure(MeasureManager.IterationType.CONTINUE_ALL)

    def start_current_measure_button_clicked(self, _):
        self.start_measure(MeasureManager.IterationType.START_CURRENT)

    def continue_current_measure_button_clicked(self, _):
        self.start_measure(MeasureManager.IterationType.CONTINUE_CURRENT)

    def stop_measure_button_clicked(self, _):
        self.measure_conductor.stop()

    def copy_cell_config(self):
        self.measure_manager.copy_cell_config()

    def paste_cell_config(self):
        self.measure_manager.paste_cell_config()

    def copy_cell_value(self):
        self.measure_manager.copy_cell_value()

    def paste_cell_value(self):
        self.measure_manager.paste_cell_value()

    def lock_gui_while_flash(self):
        self.lock_interface(True)
        self.ui.stop_flash_verify_action.setDisabled(False)

        self.ui.measure_progress_bar.setMaximum(100)
        # self.ui.measure_progress_bar.setValue(0)
        self.ui.curent_cell_progress_bar.setMaximum(100)
        # self.ui.curent_cell_progress_bar.setValue(0)

    def flash_table(self):
        if self.calibrator.state == clb.State.STOPPED:
            current_measure = self.measure_manager.get_current_measure()
            if current_measure is not None:
                if self.measure_conductor.start_flash([current_measure]):
                    self.lock_gui_while_flash()
        else:
            logging.error(
                "Калибратор не подключен, либо не находится в состоянии покоя")

    def flash_diapason_of_cell(self):
        if self.calibrator.state == clb.State.STOPPED:
            current_measure = self.measure_manager.get_current_measure()
            if current_measure is not None:
                selected_cell = self.measure_manager.get_only_selected_cell()

                if selected_cell and selected_cell.row() != 0:
                    amplitude = self.measure_manager.get_amplitude(
                        current_measure, selected_cell.row())
                    if self.measure_conductor.start_flash([current_measure],
                                                          amplitude):
                        self.lock_gui_while_flash()
        else:
            logging.error(
                "Калибратор не подключен, либо не находится в состоянии покоя")

    def verify_table(self):
        if self.calibrator.state == clb.State.STOPPED:
            current_measure = self.measure_manager.get_current_measure()
            if current_measure is not None:
                if self.measure_conductor.start_verify([current_measure]):
                    self.lock_gui_while_flash()
        else:
            logging.error(
                "Калибратор не подключен, либо не находится в состоянии покоя")

    def verify_diapason_of_cell(self):
        if self.calibrator.state == clb.State.STOPPED:
            current_measure = self.measure_manager.get_current_measure()
            if current_measure is not None:
                selected_cell = self.measure_manager.get_only_selected_cell()

                if selected_cell and selected_cell.row() != 0:
                    amplitude = self.measure_manager.get_amplitude(
                        current_measure, selected_cell.row())
                    if self.measure_conductor.start_verify([current_measure],
                                                           amplitude):
                        self.lock_gui_while_flash()
        else:
            logging.error(
                "Калибратор не подключен, либо не находится в состоянии покоя")

    def flash_all_button_clicked(self):
        if self.calibrator.state == clb.State.STOPPED:
            enabled_measures = self.measure_manager.get_enabled_measures()
            if enabled_measures:
                if self.measure_conductor.start_flash(enabled_measures):
                    self.lock_gui_while_flash()
        else:
            logging.error(
                "Калибратор не подключен, либо не находится в состоянии покоя")

    def verify_all_button_clicked(self):
        if self.calibrator.state == clb.State.STOPPED:
            enabled_measures = self.measure_manager.get_enabled_measures()
            if enabled_measures:
                if self.measure_conductor.start_verify(enabled_measures):
                    self.lock_gui_while_flash()
        else:
            logging.error(
                "Калибратор не подключен, либо не находится в состоянии покоя")

    def read_correction_tables_button_clicked(self):
        if self.calibrator.state == clb.State.STOPPED:
            enabled_measures = self.measure_manager.get_enabled_measures()
            if enabled_measures:
                if self.measure_conductor.start_read_correction_to_tables(
                        enabled_measures):
                    self.lock_gui_while_flash()
                    self.open_correction_tables = True
        else:
            logging.error(
                "Калибратор не подключен, либо не находится в состоянии покоя")

    def stop_flash_verify_button_clicked(self):
        self.measure_conductor.stop_flash_verify()

    @utils.exception_decorator
    def verify_flash_done(self):
        self.lock_interface(False)

        self.ui.measure_progress_bar.setValue(0)
        self.ui.curent_cell_progress_bar.setValue(0)

        if self.open_correction_tables:
            self.open_correction_tables = False

            correction_tables = self.measure_conductor.get_correction_tables()
            if correction_tables:
                correct_tables_dialog = CorrectionTablesDialog(
                    correction_tables, self.settings)
                correct_tables_dialog.exec()

    @utils.exception_decorator
    def open_correction_tables_from_file(self, _):
        tables_filename, _ = QtWidgets.QFileDialog.getOpenFileName(
            self, "Открыть таблицы коррекции", "", "Таблицы коррекции (*.ct)")
        if tables_filename:
            with open(tables_filename, "r") as tables_file:
                correction_tables = json.loads(tables_file.read())

            if correction_tables:
                correct_tables_dialog = CorrectionTablesDialog(
                    correction_tables, self.settings)
                correct_tables_dialog.exec()

    def show_data_table_context_menu(self):
        menu = QtWidgets.QMenu(self)

        menu.addAction(self.ui.copy_cell_value_action)
        menu.addAction(self.ui.paste_cell_value_action)

        menu.addAction(self.ui.copy_cell_config_action)
        menu.addAction(self.ui.paste_cell_config_action)
        menu.insertSeparator(self.ui.copy_cell_config_action)

        menu.addAction(self.ui.show_cell_graph_action)
        menu.insertSeparator(self.ui.show_cell_graph_action)

        menu.addAction(self.ui.flash_current_measure_action)
        menu.addAction(self.ui.verify_current_measure_action)
        menu.insertSeparator(self.ui.flash_current_measure_action)

        menu.addAction(self.ui.flash_diapason_of_cell_action)
        menu.addAction(self.ui.verify_diapason_of_cell_action)
        menu.insertSeparator(self.ui.flash_diapason_of_cell_action)

        # add other required actions
        menu.popup(QtGui.QCursor.pos())

    def open_measure_folder(self):
        if self.current_configuration_path:
            path = self.current_configuration_path.replace("/", "\\")
            os_system(f'explorer.exe "{path}"')

    def show_measures_table_context_menu(self):
        menu = QtWidgets.QMenu(self)

        open_measure_folder_action = QtWidgets.QAction(
            "Открыть каталог измерения", self)
        open_measure_folder_action.triggered.connect(self.open_measure_folder)
        menu.addAction(open_measure_folder_action)

        # add other required actions
        menu.popup(QtGui.QCursor.pos())

    @utils.exception_decorator
    def add_measure_button_clicked(self, _):
        self.measure_manager.new_measure()
        if self.current_configuration_path:
            self.save_current_configuration()
        else:
            self.save_configuration()

    @utils.exception_decorator
    def remove_measure_button_clicked(self, _):
        self.measure_manager.remove_measure(self.current_configuration_path)

    def enable_all_button_clicked(self, _):
        self.measure_manager.enable_all_measures()

    @utils.exception_decorator
    def rename_measure_button_clicked(self, _):
        self.measure_manager.rename_current_measure(
            self.current_configuration_path)

    def update_measure_status_button_clicked(self, _):
        self.measure_manager.update_all_measures_status()

    def show_equal_cell_configs_button_toggled(self, a_enable: bool):
        self.measure_manager.show_equal_cell_configs(a_enable)

    def switch_to_active_cell_action_toggled(self, a_enable: bool):
        self.settings.switch_to_active_cell = int(a_enable)

    def show_scheme_in_cell_toggled(self, a_enable: bool):
        if a_enable:
            self.ui.measure_data_view.setItemDelegate(
                SchemeInCellPainter(self.ui.measure_data_view, "#d4d4ff"))
        else:
            self.ui.measure_data_view.setItemDelegate(
                TransparentPainterForView(self.ui.measure_data_view,
                                          "#d4d4ff"))

    def measure_data_cell_clicked(self, index: QtCore.QModelIndex):
        if self.ui.show_equal_action.isChecked():
            self.measure_manager.set_cell_to_compare(index)

    def lock_cell_button_clicked(self):
        self.measure_manager.lock_selected_cells(True)

    def unlock_cell_button_clicked(self):
        self.measure_manager.lock_selected_cells(False)

    def lock_all_cells_button_clicked(self):
        self.measure_manager.lock_all_cells(True)

    def unlock_all_cells_button_clicked(self):
        self.measure_manager.lock_all_cells(False)

    def add_row_button_clicked(self, _):
        self.measure_manager.add_row_to_current_measure()

    def remove_row_button_clicked(self, _):
        self.measure_manager.remove_row_from_current_measure()

    def add_column_button_clicked(self, _):
        self.measure_manager.add_column_to_current_measure()

    def remove_column_button_clicked(self, _):
        self.measure_manager.remove_column_from_current_measure()

    def clear_table_button_clicked(self, _):
        self.measure_manager.clear_table_content()

    @utils.exception_decorator
    def open_tstlan(self, _):
        # noinspection PyTypeChecker
        if self.tstlan_dialog is None:
            self.tstlan_dialog = TstlanDialog(self.netvars, self.calibrator,
                                              self.settings)
            self.tstlan_dialog.exec()
            self.tstlan_dialog = None
        else:
            self.tstlan_dialog.activateWindow()

    @utils.exception_decorator
    def open_graphs(self, _):
        if self.graphs_dialog is None:
            graphs_data = self.measure_manager.get_data_for_graphs()
            if graphs_data:
                self.graphs_dialog = GraphDialog(graphs_data, self.settings)
                self.graphs_dialog.exec()
                self.graphs_dialog = None
        else:
            self.graphs_dialog.activateWindow()

    @utils.exception_decorator
    def open_cell_graph(self, _):
        graphs_data = self.measure_manager.get_cell_measurement_graph()
        if graphs_data:
            graph_dialog = GraphDialog(graphs_data, self.settings)
            graph_dialog.exec()

    @utils.exception_decorator
    def open_settings(self, _):
        settings_dialog = SettingsDialog(self.settings, self)
        settings_dialog.exec()

    def open_about(self):
        about_dialog = AboutDialog(self)
        about_dialog.exec()

    def open_shared_measure_parameters(self, _):
        self.measure_manager.open_shared_measure_parameters()

    def calculate_divider_coefficients_button_clicked(self, _):
        logging.error("Не реализовано ¯\\_(ツ)_/¯")

    def open_cell_configuration(self):
        self.measure_manager.open_cell_configuration()

    def set_meter(self, a_index: int):
        self.measure_manager.set_meter(MeterType(a_index))

    def set_scheme_type(self, a_index: int):
        self.measure_manager.set_scheme(SchemeType(a_index), self.ftdi_control)
        self.settings.scheme_type = a_index

    def open_meter_settings(self):
        self.measure_manager.open_meter_settings()

    def set_displayed_data(self, a_displayed_data: int):
        self.measure_manager.set_displayed_data(
            CellData.GetDataType(a_displayed_data))

    def save_configuration(self):
        result = True
        if self.current_configuration_path:
            if not self.measure_manager.is_saved():
                result = self.save_configuration_by_name(
                    self.current_configuration_path)
        else:
            result = self.save_configuration_as()
        return result

    def save_configuration_as(self):
        result = True
        # noinspection PyTypeChecker
        config_dir = QtWidgets.QFileDialog.getExistingDirectory(
            self, "Выберите каталог конфигураций",
            self.current_configuration_path)
        if config_dir:
            config_filename = f"{config_dir}"
            if self.save_configuration_by_name(config_filename):
                self.open_configuration_by_name(config_filename)
                pass
            else:
                result = False
        else:
            result = False
        return result

    def save_current_configuration(self):
        result = True
        if self.current_configuration_path:
            if not self.measure_manager.is_current_saved():
                if not self.measure_manager.save_current(
                        self.current_configuration_path):
                    QtWidgets.QMessageBox.critical(
                        self, "Ошибка", "Не удалось сохранить измерение",
                        QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok)
                    result = False
        else:
            QtWidgets.QMessageBox.critical(self, "Ошибка",
                                           f"Конфигурация не сохранена",
                                           QtWidgets.QMessageBox.Ok,
                                           QtWidgets.QMessageBox.Ok)
        return result

    def save_configuration_by_name(self, a_folder: str):
        result = True
        if self.measure_manager.save(a_folder):
            self.current_configuration_path = a_folder
            self.settings.last_configuration_path = a_folder
            self.setWindowTitle(self.current_configuration_path)
        else:
            QtWidgets.QMessageBox.critical(
                self, "Ошибка",
                f"Не удалось сохранить конфигурации в каталоге {a_folder}",
                QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok)
            result = False
        return result

    def reset_measure_manager(self):
        self.measure_manager = MeasureManager(self.ui.measures_table,
                                              self.ui.measure_data_view,
                                              self.settings, self)
        self.set_scheme_type(self.ui.scheme_combobox.currentIndex())

        self.measure_conductor = MeasureConductor(self.calibrator,
                                                  self.netvars,
                                                  self.measure_manager,
                                                  self.settings)
        self.measure_conductor.all_measures_done.connect(self.measure_done)
        self.measure_conductor.single_measure_started.connect(
            self.single_measure_started)
        self.measure_conductor.single_measure_done.connect(
            self.single_measure_done)
        self.measure_conductor.verify_flash_done.connect(
            self.verify_flash_done)

    def create_new_configuration(self):
        cancel_open = False
        if self.current_configuration_path:
            if not self.measure_manager.is_saved():
                answer = self.close_configuration()
                if answer == MainWindow.CloseConfigOptions.SAVE:
                    if not self.save_configuration():
                        cancel_open = True
                elif answer == MainWindow.CloseConfigOptions.CANCEL:
                    cancel_open = True

        if not cancel_open:
            self.current_configuration_path = ""
            self.reset_measure_manager()

    def open_configuration(self):
        cancel_open = False
        if self.current_configuration_path:
            if not self.measure_manager.is_saved():
                answer = self.close_configuration()
                if answer == MainWindow.CloseConfigOptions.SAVE:
                    if not self.save_configuration():
                        cancel_open = True
                elif answer == MainWindow.CloseConfigOptions.CANCEL:
                    cancel_open = True

        if not cancel_open:
            config_filename = QtWidgets.QFileDialog.getExistingDirectory(
                self, "Выберите каталог конфигураций",
                self.settings.last_configuration_path)
            if config_filename:
                self.settings.last_configuration_path = config_filename
                self.open_configuration_by_name(config_filename)

    def open_configuration_by_name(self, a_folder: str):
        try:
            if self.measure_manager.load_from_file(a_folder):
                self.current_configuration_path = a_folder
                self.setWindowTitle(self.current_configuration_path)
            elif a_folder:
                QtWidgets.QMessageBox.critical(
                    self, "Ошибка",
                    f'Не удалось найти файлы конфигураций в каталоге "{a_folder}"',
                    QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok)
        except FileNotFoundError:
            QtWidgets.QMessageBox.critical(
                self, "Ошибка", f'Не удалось найти каталог "{a_folder}"',
                QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok)

    @staticmethod
    def close_configuration() -> CloseConfigOptions:
        msgbox = QtWidgets.QMessageBox()
        msgbox.setWindowTitle("Предупреждение")
        msgbox.setText("Текущая конфигурация не сохранена. Выберите действие")
        save_button = msgbox.addButton("Сохранить",
                                       QtWidgets.QMessageBox.YesRole)
        no_save_button = msgbox.addButton("Не сохранять",
                                          QtWidgets.QMessageBox.AcceptRole)
        _ = msgbox.addButton("Отмена", QtWidgets.QMessageBox.AcceptRole)
        msgbox.exec()

        if msgbox.clickedButton() == save_button:
            return MainWindow.CloseConfigOptions.SAVE
        elif msgbox.clickedButton() == no_save_button:
            return MainWindow.CloseConfigOptions.DONT_SAVE
        else:
            return MainWindow.CloseConfigOptions.CANCEL

    def closeEvent(self, a_event: QtGui.QCloseEvent):
        if not self.measure_manager.is_saved() and not self.ignore_save:
            answer = self.close_configuration()

            if answer == MainWindow.CloseConfigOptions.SAVE:
                if self.save_configuration_by_name(
                        self.current_configuration_path):
                    a_event.ignore()
                    self.clb_signal_off_timer.start(self.SIGNAL_OFF_TIME_MS)
                else:
                    QtWidgets.QMessageBox.critical(
                        self, "Ошибка", "Не удалось сохранить конфигурацию")
                    a_event.ignore()

            elif answer == MainWindow.CloseConfigOptions.DONT_SAVE:
                self.ignore_save = True
                self.clb_signal_off_timer.start(self.SIGNAL_OFF_TIME_MS)
                a_event.ignore()
            else:
                a_event.ignore()

        else:
            if self.calibrator.signal_enable:
                self.calibrator.signal_enable = False
                self.clb_signal_off_timer.start(self.SIGNAL_OFF_TIME_MS)
                a_event.ignore()
            else:
                self.settings.save_qwidget_state(self.ui.mainwindow_splitter)
                self.settings.save_qwidget_state(self.ui.mainwindow_splitter_2)
                self.settings.save_qwidget_state(self.ui.measures_table)
                self.settings.save_qwidget_state(self)

                a_event.accept()
Пример #5
0
    def __init__(self):
        super().__init__()

        self.ui = MainForm()
        self.ui.setupUi(self)

        self.loader = QtGui.QMovie(":/icons/gif/loader2.gif")
        self.loader.setScaledSize(QtCore.QSize(132, 99))
        self.ui.loader_label.setMovie(self.loader)

        try:
            self.settings = Settings("./settings.ini", [
                Settings.VariableInfo(
                    a_name="fixed_step_list",
                    a_section="PARAMETERS",
                    a_type=Settings.ValueType.LIST_FLOAT,
                    a_default=[0.0001, 0.01, 0.1, 1, 10, 20, 100]),
                Settings.VariableInfo(a_name="checkbox_states",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.LIST_INT),
                Settings.VariableInfo(a_name="fixed_step_idx",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.INT),
                Settings.VariableInfo(a_name="rough_step",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=0.5),
                Settings.VariableInfo(a_name="common_step",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=0.05),
                Settings.VariableInfo(a_name="exact_step",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=0.002),
                Settings.VariableInfo(a_name="tstlan_update_time",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=0.2),
                Settings.VariableInfo(a_name="tstlan_show_marks",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.INT,
                                      a_default=0),
                Settings.VariableInfo(a_name="tstlan_marks",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.LIST_INT),
                Settings.VariableInfo(a_name="tstlan_graphs",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.LIST_INT),
                Settings.VariableInfo(a_name="tests_repeat_count",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.LIST_INT),
                Settings.VariableInfo(a_name="tests_collapsed_states",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.LIST_INT),
                Settings.VariableInfo(a_name="last_save_results_folder",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.STRING),
                Settings.VariableInfo(a_name="aux_correction_deviation",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=10),
                Settings.VariableInfo(a_name="aux_deviation",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=2),
                Settings.VariableInfo(a_name="aux_voltage_25_discretes_60v",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=18),
                Settings.VariableInfo(a_name="aux_voltage_230_discretes_60v",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=61.2),
                Settings.VariableInfo(a_name="aux_voltage_25_discretes_200v",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=61),
                Settings.VariableInfo(a_name="aux_voltage_230_discretes_200v",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=215),
                Settings.VariableInfo(a_name="aux_voltage_25_discretes_600v",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=165),
                Settings.VariableInfo(a_name="aux_voltage_230_discretes_600v",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=605),
                Settings.VariableInfo(a_name="aux_voltage_25_discretes_4v",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=1.73),
                Settings.VariableInfo(a_name="aux_voltage_230_discretes_4v",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=4.6),
            ])

            ini_ok = True
        except BadIniException:
            ini_ok = False
            QtWidgets.QMessageBox.critical(
                self, "Ошибка", 'Файл конфигурации поврежден. Пожалуйста, '
                'удалите файл "settings.ini" и запустите программу заново')
        if ini_ok:
            self.restoreGeometry(
                self.settings.get_last_geometry(self.__class__.__name__))
            self.ui.splitter.restoreState(
                self.settings.get_last_geometry(
                    self.ui.splitter.__class__.__name__ + "1"))
            self.ui.splitter_2.restoreState(
                self.settings.get_last_geometry(
                    self.ui.splitter_2.__class__.__name__ + "2"))
            self.ui.tests_tree.header().restoreState(
                self.settings.get_last_geometry(
                    self.ui.tests_tree.__class__.__name__))

            self.set_up_logger()

            self.clb_driver = clb_dll.set_up_driver(clb_dll.debug_dll_path)

            modbus_registers_count = 700
            self.usb_driver = clb_dll.UsbDrv(self.clb_driver,
                                             modbus_registers_count * 2)
            self.usb_state = clb_dll.UsbDrv.UsbState.DISABLED
            self.calibrator = clb_dll.ClbDrv(self.clb_driver)
            self.clb_state = clb.State.DISCONNECTED

            self.netvars = NetworkVariables(cfg.CLB_CONFIG_PATH,
                                            self.calibrator)
            self.netvars_db = NetvarsDatabase("./netvars.db", self)

            self.clb_signal_off_timer = QtCore.QTimer()
            # noinspection PyTypeChecker
            self.clb_signal_off_timer.timeout.connect(self.close)
            self.SIGNAL_OFF_TIME_MS = 200

            self.previous_id = 0

            self.ui.enter_settings_action.triggered.connect(self.open_settings)

            self.source_mode_widget = self.set_up_source_mode_widget()
            self.show()

            self.tests = tests_factory.create_tests(self.calibrator,
                                                    self.netvars,
                                                    self.netvars_db,
                                                    self.settings)

            self.tests_widget = TestsTreeWidget(self.tests, self.ui.tests_tree,
                                                self.settings)
            self.tests_widget.show_graph_requested.connect(
                self.show_test_graph)
            self.tests_widget.show_errors_requested.connect(
                self.show_test_errors)
            self.graphs_dialogs: Dict[Tuple[str, str], QtWidgets.QDialog] = {}
            self.errors_dialogs: Dict[Tuple[str, str], QtWidgets.QDialog] = {}

            self.test_conductor = TestsConductor(self.tests)
            self.ui.autocheck_start_button.clicked.connect(
                self.autocheck_button_clicked)
            self.test_conductor.tests_done.connect(self.stop_autocheck)
            self.test_conductor.test_status_changed.connect(
                self.set_test_status)

            self.source_mode_widget.ui.open_tstlan_button.clicked.connect(
                self.open_tstlan)

            self.ui.save_button.clicked.connect(self.save_button_clicked)
            self.ui.load_button.clicked.connect(self.load_results)
            self.ui.clear_results_button.clicked.connect(self.clear_results)

            self.tick_timer = QtCore.QTimer(self)
            self.tick_timer.timeout.connect(self.tick)
            self.tick_timer.start(10)
        else:
            self.close()
Пример #6
0
class MainWindow(QtWidgets.QMainWindow):
    clb_list_changed = QtCore.pyqtSignal([list])
    usb_status_changed = QtCore.pyqtSignal(clb.State)
    signal_enable_changed = QtCore.pyqtSignal(bool)

    TEST_START_ROW = 1
    CHECK_BOX_COLUMN = 0

    STATUS_COLUMN = 2

    def __init__(self):
        super().__init__()

        self.ui = MainForm()
        self.ui.setupUi(self)

        self.loader = QtGui.QMovie(":/icons/gif/loader2.gif")
        self.loader.setScaledSize(QtCore.QSize(132, 99))
        self.ui.loader_label.setMovie(self.loader)

        try:
            self.settings = Settings("./settings.ini", [
                Settings.VariableInfo(
                    a_name="fixed_step_list",
                    a_section="PARAMETERS",
                    a_type=Settings.ValueType.LIST_FLOAT,
                    a_default=[0.0001, 0.01, 0.1, 1, 10, 20, 100]),
                Settings.VariableInfo(a_name="checkbox_states",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.LIST_INT),
                Settings.VariableInfo(a_name="fixed_step_idx",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.INT),
                Settings.VariableInfo(a_name="rough_step",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=0.5),
                Settings.VariableInfo(a_name="common_step",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=0.05),
                Settings.VariableInfo(a_name="exact_step",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=0.002),
                Settings.VariableInfo(a_name="tstlan_update_time",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=0.2),
                Settings.VariableInfo(a_name="tstlan_show_marks",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.INT,
                                      a_default=0),
                Settings.VariableInfo(a_name="tstlan_marks",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.LIST_INT),
                Settings.VariableInfo(a_name="tstlan_graphs",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.LIST_INT),
                Settings.VariableInfo(a_name="tests_repeat_count",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.LIST_INT),
                Settings.VariableInfo(a_name="tests_collapsed_states",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.LIST_INT),
                Settings.VariableInfo(a_name="last_save_results_folder",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.STRING),
                Settings.VariableInfo(a_name="aux_correction_deviation",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=10),
                Settings.VariableInfo(a_name="aux_deviation",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=2),
                Settings.VariableInfo(a_name="aux_voltage_25_discretes_60v",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=18),
                Settings.VariableInfo(a_name="aux_voltage_230_discretes_60v",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=61.2),
                Settings.VariableInfo(a_name="aux_voltage_25_discretes_200v",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=61),
                Settings.VariableInfo(a_name="aux_voltage_230_discretes_200v",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=215),
                Settings.VariableInfo(a_name="aux_voltage_25_discretes_600v",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=165),
                Settings.VariableInfo(a_name="aux_voltage_230_discretes_600v",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=605),
                Settings.VariableInfo(a_name="aux_voltage_25_discretes_4v",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=1.73),
                Settings.VariableInfo(a_name="aux_voltage_230_discretes_4v",
                                      a_section="PARAMETERS",
                                      a_type=Settings.ValueType.FLOAT,
                                      a_default=4.6),
            ])

            ini_ok = True
        except BadIniException:
            ini_ok = False
            QtWidgets.QMessageBox.critical(
                self, "Ошибка", 'Файл конфигурации поврежден. Пожалуйста, '
                'удалите файл "settings.ini" и запустите программу заново')
        if ini_ok:
            self.restoreGeometry(
                self.settings.get_last_geometry(self.__class__.__name__))
            self.ui.splitter.restoreState(
                self.settings.get_last_geometry(
                    self.ui.splitter.__class__.__name__ + "1"))
            self.ui.splitter_2.restoreState(
                self.settings.get_last_geometry(
                    self.ui.splitter_2.__class__.__name__ + "2"))
            self.ui.tests_tree.header().restoreState(
                self.settings.get_last_geometry(
                    self.ui.tests_tree.__class__.__name__))

            self.set_up_logger()

            self.clb_driver = clb_dll.set_up_driver(clb_dll.debug_dll_path)

            modbus_registers_count = 700
            self.usb_driver = clb_dll.UsbDrv(self.clb_driver,
                                             modbus_registers_count * 2)
            self.usb_state = clb_dll.UsbDrv.UsbState.DISABLED
            self.calibrator = clb_dll.ClbDrv(self.clb_driver)
            self.clb_state = clb.State.DISCONNECTED

            self.netvars = NetworkVariables(cfg.CLB_CONFIG_PATH,
                                            self.calibrator)
            self.netvars_db = NetvarsDatabase("./netvars.db", self)

            self.clb_signal_off_timer = QtCore.QTimer()
            # noinspection PyTypeChecker
            self.clb_signal_off_timer.timeout.connect(self.close)
            self.SIGNAL_OFF_TIME_MS = 200

            self.previous_id = 0

            self.ui.enter_settings_action.triggered.connect(self.open_settings)

            self.source_mode_widget = self.set_up_source_mode_widget()
            self.show()

            self.tests = tests_factory.create_tests(self.calibrator,
                                                    self.netvars,
                                                    self.netvars_db,
                                                    self.settings)

            self.tests_widget = TestsTreeWidget(self.tests, self.ui.tests_tree,
                                                self.settings)
            self.tests_widget.show_graph_requested.connect(
                self.show_test_graph)
            self.tests_widget.show_errors_requested.connect(
                self.show_test_errors)
            self.graphs_dialogs: Dict[Tuple[str, str], QtWidgets.QDialog] = {}
            self.errors_dialogs: Dict[Tuple[str, str], QtWidgets.QDialog] = {}

            self.test_conductor = TestsConductor(self.tests)
            self.ui.autocheck_start_button.clicked.connect(
                self.autocheck_button_clicked)
            self.test_conductor.tests_done.connect(self.stop_autocheck)
            self.test_conductor.test_status_changed.connect(
                self.set_test_status)

            self.source_mode_widget.ui.open_tstlan_button.clicked.connect(
                self.open_tstlan)

            self.ui.save_button.clicked.connect(self.save_button_clicked)
            self.ui.load_button.clicked.connect(self.load_results)
            self.ui.clear_results_button.clicked.connect(self.clear_results)

            self.tick_timer = QtCore.QTimer(self)
            self.tick_timer.timeout.connect(self.tick)
            self.tick_timer.start(10)
        else:
            self.close()

    def set_up_logger(self):
        log = QTextEditLogger(self, self.ui.log_text_edit)
        log.setFormatter(
            logging.Formatter('%(asctime)s - %(message)s', datefmt='%H:%M:%S'))

        logging.getLogger().addHandler(log)
        # logging.getLogger().setLevel(logging.DEBUG)
        logging.getLogger().setLevel(logging.INFO)
        # logging.getLogger().setLevel(logging.WARN)

    def set_up_source_mode_widget(self) -> SourceModeWidget:
        source_mode_widget = SourceModeWidget(self.settings, self.calibrator,
                                              self.netvars, self)
        self.clb_list_changed.connect(source_mode_widget.update_clb_list)
        self.usb_status_changed.connect(source_mode_widget.update_clb_status)
        self.signal_enable_changed.connect(
            source_mode_widget.signal_enable_changed)
        self.ui.source_mode_layout.addWidget(source_mode_widget)
        return source_mode_widget

    def tick(self):
        self.usb_tick()
        self.test_conductor.tick()

    def usb_tick(self):
        self.usb_driver.tick()

        if self.usb_driver.is_dev_list_changed():
            self.clb_list_changed.emit(self.usb_driver.get_dev_list())

        if self.usb_driver.is_status_changed():
            self.usb_state = self.usb_driver.get_status()

        current_state = clb.State.DISCONNECTED
        if self.usb_state == clb_dll.UsbDrv.UsbState.CONNECTED:
            if self.calibrator.signal_enable_changed():
                self.signal_enable_changed.emit(self.calibrator.signal_enable)

            if not self.calibrator.signal_enable:
                current_state = clb.State.STOPPED
            elif not self.calibrator.is_signal_ready():
                current_state = clb.State.WAITING_SIGNAL
            else:
                current_state = clb.State.READY

        if self.clb_state != current_state:
            self.clb_state = current_state
            self.calibrator.state = current_state
            self.usb_status_changed.emit(self.clb_state)

        current_id = self.netvars.id.get()
        if current_id != self.previous_id:
            if current_id != 0:
                self.previous_id = current_id
                self.clear_results()

    def lock_interface(self, a_lock):
        self.source_mode_widget.ui.control_box.setDisabled(a_lock)
        self.tests_widget.lock_interface(a_lock)
        self.ui.load_button.setDisabled(a_lock)
        self.ui.save_button.setDisabled(a_lock)
        self.ui.clear_results_button.setDisabled(a_lock)

    def autocheck_button_clicked(self):
        try:
            if self.test_conductor.started():
                self.test_conductor.stop()
                self.stop_autocheck()
            else:
                self.start_autocheck()
        except Exception as err:
            logging.debug(utils.exception_handler(err))

    def start_autocheck(self):
        if self.calibrator.state != clb.State.DISCONNECTED:
            aux_group_enabled = self.tests_widget.is_group_enabled(
                "Предварительные стабилизаторы")
            if aux_group_enabled is None:
                logging.warning(
                    'Группа Предварительные стабилизаторы" не найдена')

            elif self.netvars.software_revision.get(
            ) < 295 and aux_group_enabled:
                QtWidgets.QMessageBox.warning(
                    self, "Ошибка",
                    "Тест предварительных стабилизаторов доступен для "
                    "прошивок старше 294 ревизии", QtWidgets.QMessageBox.Yes,
                    QtWidgets.QMessageBox.Yes)
            elif self.netvars.source_manual_mode_password.get(
            ) != clb.MANUAL_MODE_ENABLE_PASSWORD:
                self.lock_interface(True)
                self.test_conductor.set_enabled_tests(
                    self.tests_widget.get_tests_repeat_count())
                self.ui.autocheck_start_button.setText("Остановить")
                self.test_conductor.start()

                self.ui.loader_label.show()
                self.loader.start()
            else:
                logging.warning(
                    "Включен ручной режим. Перезагрузите калибратор, чтобы запустить проверку"
                )
        else:
            logging.warning(
                "Калибратор не подключен, невозможно провести проверку")

    def stop_autocheck(self):
        self.lock_interface(False)
        self.ui.autocheck_start_button.setText("Старт")
        logging.info("Проверка завершена")

        self.ui.loader_label.hide()
        self.loader.stop()

    def set_test_status(self, a_group_name, a_test_name: str,
                        a_status: tests_base.ClbTest.Status,
                        a_success_count: int):
        try:
            self.tests_widget.set_test_status(a_group_name, a_test_name,
                                              a_status, a_success_count)
        except AssertionError as err:
            logging.debug(utils.exception_handler(err))

    def open_tstlan(self):
        try:
            tstlan_dialog = TstlanDialog(self.netvars, self.calibrator,
                                         self.settings, self)
            tstlan_dialog.exec()
        except Exception as err:
            logging.debug(utils.exception_handler(err))

    def show_test_graph(self, a_group: str, a_name: str):
        try:
            graph_data = self.test_conductor.get_test_graph(a_group, a_name)
            if graph_data:
                try:
                    graphs_dialog = self.graphs_dialogs[(a_group, a_name)]
                    graphs_dialog.activateWindow()
                except KeyError:
                    graphs_dialog = TestGraphDialog(graph_data, self.settings,
                                                    self)
                    graphs_dialog.setWindowTitle(
                        f'Графики теста "{a_group}: {a_name}"')
                    self.graphs_dialogs[(a_group, a_name)] = graphs_dialog
                    self.test_conductor.graphs_have_been_updated.connect(
                        graphs_dialog.update_graphs)
                    graphs_dialog.exec()
                    del self.graphs_dialogs[(a_group, a_name)]
            else:
                logging.warning("График для выбранного измерения не создан")
        except Exception as err:
            logging.debug(utils.exception_handler(err))

    def show_test_errors(self, a_group: str, a_name: str):
        try:
            errors_list = self.test_conductor.get_test_errors(a_group, a_name)
            has_errors = True if any(error != ""
                                     for error in errors_list) else False
            if has_errors:
                try:
                    errors_dialog = self.errors_dialogs[(a_group, a_name)]
                    errors_dialog.activateWindow()
                except KeyError:
                    nl = "\n"
                    errors_list = [
                        f'<p style=" color:#ff0000;">Тест №{num + 1}</p>{error.replace(nl, "<br>")}'
                        for num, error in enumerate(errors_list)
                    ]

                    errors_dialog = DialogWithText(errors_list, self.settings,
                                                   self)
                    errors_dialog.setWindowTitle(
                        f'Ошибки теста "{a_group}: {a_name}"')
                    self.errors_dialogs[(a_group, a_name)] = errors_dialog
                    errors_dialog.exec()
                    del self.errors_dialogs[(a_group, a_name)]
            else:
                logging.warning("Выбранный тест не содержит ошибок")
        except Exception as err:
            logging.debug(utils.exception_handler(err))

    @utils.exception_decorator
    def save_button_clicked(self, _):
        suggest_filename = f"{QtCore.QDate.currentDate().toString('yyyyMMdd')} N4-25 №{self.netvars.id.get()}"
        chosen_file, _ = QtWidgets.QFileDialog.getSaveFileName(
            self, "Сохранить результаты",
            f"{self.settings.last_save_results_folder}/{suggest_filename}",
            "Результаты проверки (*.car)")
        if chosen_file != "":
            results = {}
            for test in self.tests:
                test_results = self.test_conductor.get_test_results(
                    test.group(), test.name())
                results[
                    f"{test.group()}:{test.name()}"] = test_results.data_to_serialize(
                    )
            results["log"] = self.ui.log_text_edit.toPlainText()

            with open(chosen_file, 'w') as file:
                file.write(json.dumps(results, indent=4))

    @utils.exception_decorator
    def load_results(self, _):
        chosen_file, _ = QtWidgets.QFileDialog.getOpenFileName(
            self, "Выберите файл", self.settings.last_save_results_folder,
            "Результаты проверки (*.car)")
        if chosen_file != "":
            self.settings.last_save_results_folder = chosen_file[:chosen_file.
                                                                 rfind("/")]

            with open(chosen_file, 'r') as file:
                test_results: Dict[str, Dict] = json.load(file)

            self.ui.log_text_edit.setPlainText(test_results["log"])
            del test_results["log"]

            for test_name in test_results.keys():
                sep = test_name.find(':')
                group, name = test_name[:sep], test_name[sep + 1:]

                try:
                    self.test_conductor.set_test_results(
                        group, name, test_results[test_name])
                except ValueError:
                    logging.warning(
                        f"Тест {group}: {name} не найден! Результаты не восстановлены"
                    )

    def clear_results(self):
        for test in self.tests:
            test_results = self.test_conductor.get_test_results(
                test.group(), test.name())
            test_results.delete_results()
            self.tests_widget.set_test_status(
                test.group(), test.name(), test_results.get_final_status(),
                test_results.get_success_results_count())

    def open_settings(self):
        try:
            settings_dialog = SettingsDialog(self.settings, self.netvars_db,
                                             self)
            settings_dialog.exec()
        except Exception as err:
            logging.debug(utils.exception_handler(err))

    def closeEvent(self, a_event: QtGui.QCloseEvent):
        if self.calibrator.signal_enable:
            self.calibrator.signal_enable = False
            self.clb_signal_off_timer.start(self.SIGNAL_OFF_TIME_MS)
            a_event.ignore()
        else:
            self.settings.save_geometry(
                self.ui.splitter.__class__.__name__ + "1",
                self.ui.splitter.saveState())
            self.settings.save_geometry(
                self.ui.splitter_2.__class__.__name__ + "2",
                self.ui.splitter_2.saveState())
            self.settings.save_geometry(
                self.ui.tests_tree.__class__.__name__,
                self.ui.tests_tree.header().saveState())
            self.settings.save_geometry(self.__class__.__name__,
                                        self.saveGeometry())
            self.tests_widget.save()
            a_event.accept()
Пример #7
0
class MainWindow(QtWidgets.QMainWindow):
    measures_filename = "main_table.csv"
    default_name_template = "report"

    MEASURE_TYPE_TO_TEMPLATE_PATH = {
        UpmsMeasure.MeasureType.MECH_STOPWATCH:
        ("Templates/ms_template.xlsx", "Templates/ms_template.ods"),
        UpmsMeasure.MeasureType.ELEC_STOPWATCH:
        ("Templates/es_template.xlsx", "Templates/es_template.ods"),
        UpmsMeasure.MeasureType.CLOCK:
        ("Templates/clock_template.xlsx", "Templates/clock_template.ods"),
    }

    def __init__(self):
        super().__init__()

        self.ui = MainForm()
        self.ui.setupUi(self)

        try:
            self.settings = settings.get_ini_settings(
                os.path.join(self.get_application_path(), "settings.ini"))
            ini_ok = True
        except BadIniException:
            ini_ok = False
            QtWidgets.QMessageBox.critical(self, Text.get("err"),
                                           Text.get("ini_err"))
        if ini_ok:
            self.settings.restore_qwidget_state(self)
            self.settings.restore_qwidget_state(self.ui.mw_splitter_1)
            self.settings.restore_qwidget_state(self.ui.measures_table)

            self.ui.download_progress_bar.setHidden(True)

            if ENGLISH_VERSION:
                self.ui.russian_language_action.setVisible(False)
                self.settings.language = Text.Lang.EN

            self.translator = QtCore.QTranslator(
                QtWidgets.QApplication.instance())
            self.install_translator(self.settings.language)

            if self.settings.language == Text.Lang.EN:
                self.ui.english_language_action.setChecked(True)
            else:
                self.ui.russian_language_action.setChecked(True)

            self.set_up_logger()

            self.ui.measures_table.setItemDelegate(
                TransparentPainterForView(self.ui.measures_table, "#d4d4ff"))
            self.ui.download_path_edit.setText(self.settings.save_folder_path)

            self.ui.ip_combobox.setEditText(self.settings.ip)
            self.ui.download_path_edit.setText(self.settings.path)
            self.ui.name_template_edit.setText(self.settings.name_template)
            self.ui.save_folder_edit.setText(self.settings.save_folder)

            self.db = UpmsDatabase(
                os.path.join(self.get_application_path(), "database.db"))
            self.measures_table_model = None
            self.proxy = None
            self.update_model()

            self.bcast_sockets = {}
            self.get_broadcast_ips()

            self.show()
            self.connect_all()

            self.ui.get_ip_button.click()
        else:
            self.close()

    def install_translator(self, a_language: Text.Lang):
        try:
            # Для программы, собранной pyinstaller
            base_path = sys._MEIPASS
        except AttributeError:
            base_path = "."

        translate_file = Text.LANG_TO_QT_TRANSLATE[a_language]
        self.translator.load(os.path.join(base_path, translate_file))
        QtWidgets.QApplication.instance().installTranslator(self.translator)
        self.ui.retranslateUi(self)
        Text.set_language(a_language)

    def connect_all(self):
        self.ui.open_about_action.triggered.connect(self.open_about)
        self.ui.download_from_upms_button.clicked.connect(
            self.download_from_upms_button_clicked)
        self.ui.ip_combobox.editTextChanged.connect(self.ip_changed)
        self.ui.download_path_edit.textChanged.connect(self.path_changed)
        self.ui.name_template_edit.textChanged.connect(
            self.name_template_changed)
        self.ui.save_folder_edit.textChanged.connect(self.save_folder_changed)

        self.ui.get_ip_button.clicked.connect(self.get_ip_button_clicked)

        self.ui.input_result_button.clicked.connect(
            self.input_result_button_clicked)
        self.ui.create_report_button.clicked.connect(
            self.create_report_button_clicked)
        self.ui.remove_selected_button.clicked.connect(
            self.remove_selected_button_clicked)

        self.ui.choose_download_path_button.clicked.connect(
            self.choose_download_path_button_clicked)
        self.ui.choose_save_folder_path_edit.clicked.connect(
            self.choose_save_folder_path_button_clicked)
        self.ui.extra_params_button.clicked.connect(
            self.extra_params_button_clicked)

        self.ui.russian_language_action.triggered.connect(
            self.russian_language_chosen)
        self.ui.english_language_action.triggered.connect(
            self.english_language_chosen)

        group = QtWidgets.QActionGroup(self)
        group.addAction(self.ui.russian_language_action)
        group.addAction(self.ui.english_language_action)

    def set_up_logger(self):
        log = qt_utils.QTextEditLogger(self.ui.log_text_edit)
        log.setFormatter(
            logging.Formatter('%(asctime)s - %(message)s', datefmt='%H:%M:%S'))

        file_log = RotatingFileHandler(os.path.join(
            self.get_application_path(), "upms_1v_pc.log"),
                                       maxBytes=30 * 1024 * 1024,
                                       backupCount=3,
                                       encoding='utf8')
        file_log.setLevel(logging.DEBUG)
        file_log.setFormatter(
            logging.Formatter('%(asctime)s - %(levelname)s - %(message)s',
                              datefmt='%H:%M:%S'))

        logging.getLogger().addHandler(file_log)
        logging.getLogger().addHandler(log)
        logging.getLogger().setLevel(logging.WARNING)

    def update_model(self):
        self.measures_table_model = UpmsDatabaseModel(self.db, self)
        self.proxy = QtCore.QSortFilterProxyModel()
        self.proxy.setSourceModel(self.measures_table_model)
        self.ui.measures_table.setModel(self.proxy)
        self.ui.measures_table.resizeRowsToContents()

    def download_measures_list(self, a_download_filepath: str) -> bool:
        result = False
        ip = self.ui.ip_combobox.currentText()
        try:
            socket.inet_aton(ip)
        except socket.error:
            QtWidgets.QMessageBox.critical(self, Text.get("err"),
                                           Text.get("ip_format_err"),
                                           QtWidgets.QMessageBox.Ok,
                                           QtWidgets.QMessageBox.Ok)
        else:
            try:
                files_list = upms_tftp.get_files_list(
                    self.ui.ip_combobox.currentText())
            except ConnectionResetError:
                QtWidgets.QMessageBox.critical(self, Text.get("err"),
                                               Text.get("connection_err"),
                                               QtWidgets.QMessageBox.Ok,
                                               QtWidgets.QMessageBox.Ok)
            else:
                if files_list is not None:
                    if self.measures_filename in files_list:
                        try:
                            upms_tftp.download_file_by_tftp(
                                ip, self.measures_filename,
                                a_download_filepath)
                            result = True
                        except FileNotFoundError:
                            QtWidgets.QMessageBox.critical(
                                self, Text.get("err"), Text.get("path_err"),
                                QtWidgets.QMessageBox.Ok,
                                QtWidgets.QMessageBox.Ok)
                    else:
                        QtWidgets.QMessageBox.critical(
                            self, Text.get("err"),
                            Text.get("main_table_not_found_err").format(
                                self.measures_filename),
                            QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok)
                else:
                    QtWidgets.QMessageBox.critical(self, Text.get("err"),
                                                   Text.get("download_err"),
                                                   QtWidgets.QMessageBox.Ok,
                                                   QtWidgets.QMessageBox.Ok)
        return result

    def download_photo(self, a_measure_id: int, a_files_list: List[str],
                       a_download_folder: str):
        photo_name = "{}.jpg".format(a_measure_id)
        download_path = a_download_folder.rstrip(os.sep) + os.sep + photo_name
        if photo_name in a_files_list:
            logging.warning("Download {}".format(photo_name))
            upms_tftp.download_file_by_tftp(self.ui.ip_combobox.currentText(),
                                            photo_name, download_path)

    @exception_decorator
    def download_from_upms_button_clicked(self, _):
        download_folder = self.ui.download_path_edit.text()
        if download_folder and os.path.isdir(download_folder):
            download_filepath = download_folder.rstrip(
                os.sep) + os.sep + self.measures_filename

            if self.download_measures_list(download_filepath):
                with open(download_filepath, 'r',
                          encoding='utf8') as measures_list_file:
                    # Первая строка - заголовок
                    measures_list = [
                        file for idx, file in enumerate(measures_list_file)
                        if idx != 0
                    ]

                update_all = False
                upms_files_list = upms_tftp.get_files_list(
                    self.ui.ip_combobox.currentText())
                self.ui.download_progress_bar.setHidden(False)
                for number, measure in enumerate(measures_list):
                    self.ui.download_progress_bar.setValue(
                        number / (len(upms_files_list) - 1) *
                        self.ui.download_progress_bar.maximum())

                    measure_params = [
                        meas.strip() for meas in measure.strip().split(',')
                    ]
                    upms_measure = UpmsMeasure(*measure_params)
                    upms_prev_measure = self.db.get(upms_measure.id)

                    if upms_measure != upms_prev_measure:
                        if upms_prev_measure is None:
                            self.db.add(upms_measure)
                            self.download_photo(upms_measure.id,
                                                upms_files_list,
                                                download_folder)
                        else:
                            if update_all:
                                res = QtWidgets.QMessageBox.Yes
                            else:
                                res = QtWidgets.QMessageBox.question(
                                    self, Text.get("warning"),
                                    Text.get("ask_overwrite").format(
                                        upms_measure.id),
                                    QtWidgets.QMessageBox.Yes
                                    | QtWidgets.QMessageBox.YesAll
                                    | QtWidgets.QMessageBox.No
                                    | QtWidgets.QMessageBox.Cancel,
                                    QtWidgets.QMessageBox.Yes)
                            if res == QtWidgets.QMessageBox.Yes:
                                self.db.update(upms_measure)
                                self.download_photo(upms_measure.id,
                                                    upms_files_list,
                                                    download_folder)
                            elif res == QtWidgets.QMessageBox.YesAll:
                                self.db.update(upms_measure)
                                self.download_photo(upms_measure.id,
                                                    upms_files_list,
                                                    download_folder)
                                update_all = True
                            elif res == QtWidgets.QMessageBox.Cancel:
                                QtWidgets.QMessageBox.warning(
                                    self, Text.get("warning"),
                                    Text.get("download_canceled"),
                                    QtWidgets.QMessageBox.Ok,
                                    QtWidgets.QMessageBox.Ok)
                                break
                    elif not os.path.isfile(
                            os.path.join(download_folder.rstrip(os.sep),
                                         "{}.jpg".format(upms_measure.id))):
                        # Докачиваем файл, если запись в БД есть, а файла нет
                        self.download_photo(upms_measure.id, upms_files_list,
                                            download_folder)
                else:
                    QtWidgets.QMessageBox.information(
                        self, Text.get("info"), Text.get("success_download"),
                        QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok)

                self.ui.download_progress_bar.setValue(0)
                self.ui.download_progress_bar.setHidden(True)
                self.update_model()

        else:
            QtWidgets.QMessageBox.critical(self, Text.get("err"),
                                           Text.get("path_err"),
                                           QtWidgets.QMessageBox.Ok,
                                           QtWidgets.QMessageBox.Ok)

    def ip_changed(self, a_ip):
        self.settings.ip = a_ip

    def path_changed(self, a_path):
        self.settings.path = a_path

    def name_template_changed(self, a_name_template):
        self.settings.name_template = a_name_template

    def save_folder_changed(self, a_save_folder):
        self.settings.save_folder = a_save_folder

    def get_broadcast_ips(self):
        localhost = QtNetwork.QHostAddress(QtNetwork.QHostAddress.LocalHost)
        for _if in QtNetwork.QNetworkInterface.allInterfaces():
            for addr in _if.addressEntries():
                if addr.ip().protocol() == QtNetwork.QAbstractSocket.IPv4Protocol and not addr.netmask().isNull() and \
                        addr.ip() != localhost:
                    bcast = QtNetwork.QHostAddress(
                        addr.ip().toIPv4Address() |
                        ((1 << 32) - 1 -
                         addr.netmask().toIPv4Address()))  # bit not
                    udp_sock = QtNetwork.QUdpSocket(self)
                    udp_sock.bind(addr.ip())

                    self.bcast_sockets[bcast.toString()] = udp_sock
                    udp_sock.readyRead.connect(self.read_ip_from_socket)

    def get_ip_button_clicked(self):
        for ip, sock in self.bcast_sockets.items():
            sock.writeDatagram("upms_1v_get_ip".encode('ascii'),
                               QtNetwork.QHostAddress(ip), 5007)

    @exception_decorator
    def read_ip_from_socket(self):
        self.ui.ip_combobox.clear()
        for ip, sock in self.bcast_sockets.items():
            while sock.hasPendingDatagrams():
                datagram = sock.receiveDatagram()
                data = bytes(datagram.data()).decode(encoding='ascii')
                ip, _ = data.split(';')
                try:
                    socket.inet_aton(ip)
                    self.ui.ip_combobox.addItem(ip)
                except socket.error:
                    logging.error("{} is not valid ip-address".format(ip))

    @exception_decorator_print
    def input_result_button_clicked(self, _):
        rows = self.ui.measures_table.selectionModel().selectedRows()
        if rows:
            for idx in rows:
                real_row = self.proxy.mapToSource(idx).row()

                self.ui.measures_table.selectionModel().setCurrentIndex(
                    self.measures_table_model.index(idx.row(), 0),
                    QtCore.QItemSelectionModel.ClearAndSelect
                    | QtCore.QItemSelectionModel.Rows)
                files_path = self.ui.download_path_edit.text()
                if files_path and os.path.isdir(files_path):
                    upms_measure = self.measures_table_model.get_upms_measure_by_row(
                        real_row)
                    dialog = ResultInputDialog(upms_measure, files_path,
                                               self.settings, self)
                    res = dialog.exec()
                    if res == QtWidgets.QDialog.Accepted:
                        new_result = dialog.get_result()
                        self.measures_table_model.update_result(
                            real_row, new_result)
                        logging.warning(upms_measure.result)
                        # Для сохранения состояния (иначе не вызывается closeEvent)
                        dialog.close()
                    else:
                        break
                else:
                    QtWidgets.QMessageBox.critical(self, Text.get("err"),
                                                   Text.get("path_err"),
                                                   QtWidgets.QMessageBox.Ok,
                                                   QtWidgets.QMessageBox.Ok)
        else:
            QtWidgets.QMessageBox.information(self, Text.get("info"),
                                              Text.get("selection_info"),
                                              QtWidgets.QMessageBox.Ok,
                                              QtWidgets.QMessageBox.Ok)

    # def get_template_file(self, a_measure_type) -> str:
    #     for path in self.MEASURE_TYPE_TO_TEMPLATE_PATH[a_measure_type]:
    #         if os.path.isfile(path):
    #             return path
    #     return ""

    @staticmethod
    def get_accessible_name(a_name_template, a_save_folder,
                            a_extension: str) -> str:
        number = 2
        name = a_name_template
        while os.path.isfile("{}{}{}{}".format(a_save_folder.rstrip(os.sep),
                                               os.sep, name, a_extension)):
            name = "{}_{}".format(a_name_template, number)
            number += 1
        return "{}{}".format(name, a_extension)

    @staticmethod
    def get_application_path():
        if getattr(sys, 'frozen', False):
            application_path = os.path.dirname(sys.executable)
        else:
            application_path = os.path.dirname(__file__)
        return application_path

    def create_protocol_generator(
        self, a_name_template, a_save_folder, a_measure_type,
        a_generator: Type[pg.UpmsProtocolGenerator]
    ) -> Optional[pg.UpmsProtocolGenerator]:
        extension = a_generator.protocol_ext()
        template_files = \
            list(filter(lambda s: s.endswith(extension), self.MEASURE_TYPE_TO_TEMPLATE_PATH[a_measure_type]))

        template_filename = os.path.join(self.get_application_path(),
                                         template_files[0])

        if os.path.isfile(template_filename):
            filename = self.get_accessible_name(a_name_template, a_save_folder,
                                                extension)
            report_path = os.path.join(a_save_folder.rstrip(os.sep), filename)
            shutil.copyfile(template_filename, report_path)

            return a_generator(report_path)
        else:
            QtWidgets.QMessageBox.critical(
                self, Text.get("err"),
                Text.get("templates_are_not_found").format(template_filename),
                QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok)
            return None

    @exception_decorator
    def create_report(self, a_name_template, a_save_folder,
                      a_measure_type: UpmsMeasure.MeasureType, a_photos_path,
                      a_upms_measures: List[UpmsMeasure]):
        protocol_generators = []
        if True:
            generator = self.create_protocol_generator(
                a_name_template, a_save_folder, a_measure_type,
                pg.ExcelProtocolGenerator)
            if generator is not None:
                protocol_generators.append(generator)

        if False:
            generator = self.create_protocol_generator(
                a_name_template, a_save_folder, a_measure_type,
                pg.CalcProtocolGenerator)
            if generator is not None:
                protocol_generators.append(generator)

        for protocol_gen in protocol_generators:
            if protocol_gen.is_template_ok():
                protocol_gen.insert_measures(a_upms_measures)
                protocol_gen.insert_extra_parameters(self.db.get_parameters())
                protocol_gen.insert_photos(a_photos_path, a_upms_measures)

                protocol_gen.save()

                QtWidgets.QMessageBox.information(
                    self, Text.get("info"),
                    Text.get("success_generated").format(
                        protocol_gen.get_report_path()),
                    QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok)
                if os.name == 'nt':
                    os.startfile(protocol_gen.get_report_path())
                else:
                    opener = "open" if sys.platform == "darwin" else "xdg-open"
                    subprocess.call([opener, protocol_gen.get_report_path()])
            else:
                QtWidgets.QMessageBox.critical(
                    self, Text.get("err"),
                    Text.get("data_sheet_not_found").format(
                        protocol_gen.get_report_path()),
                    QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok)

    @exception_decorator
    def create_report_button_clicked(self, _):
        rows = self.ui.measures_table.selectionModel().selectedRows()
        if rows:
            types = [
                self.measures_table_model.get_type(
                    self.proxy.mapToSource(idx).row()) for idx in rows
            ]
            if len(types) == types.count(types[0]):
                save_folder = self.ui.save_folder_edit.text()
                if save_folder and os.path.isdir(save_folder):
                    if self.ui.download_path_edit.text():
                        name_template = self.ui.name_template_edit.text() if self.ui.name_template_edit.text() else \
                            self.default_name_template
                        upms_measures = [
                            self.measures_table_model.get_upms_measure_by_row(
                                self.proxy.mapToSource(idx).row())
                            for idx in rows
                        ]
                        self.create_report(name_template, save_folder,
                                           types[0],
                                           self.ui.download_path_edit.text(),
                                           upms_measures)
                    else:
                        QtWidgets.QMessageBox.critical(
                            self, Text.get("err"), Text.get("path_err"),
                            QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok)
                else:
                    QtWidgets.QMessageBox.critical(
                        self, Text.get("err"), Text.get("save_folder_error"),
                        QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok)
            else:
                QtWidgets.QMessageBox.critical(self, Text.get("err"),
                                               Text.get("same_type_err"),
                                               QtWidgets.QMessageBox.Ok,
                                               QtWidgets.QMessageBox.Ok)
        else:
            QtWidgets.QMessageBox.information(self, Text.get("info"),
                                              Text.get("selection_info"),
                                              QtWidgets.QMessageBox.Ok,
                                              QtWidgets.QMessageBox.Ok)

    def remove_selected_button_clicked(self, _):
        rows = self.ui.measures_table.selectionModel().selectedRows()
        if rows:
            res = QtWidgets.QMessageBox.question(
                self, Text.get("confirm"), Text.get("delete_confirm"),
                QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel,
                QtWidgets.QMessageBox.Cancel)
            if res == QtWidgets.QMessageBox.Ok:
                real_rows = [self.proxy.mapToSource(r).row() for r in rows]
                real_rows.sort(reverse=True)
                for row in real_rows:
                    self.measures_table_model.remove_row(row)
        else:
            QtWidgets.QMessageBox.information(self, Text.get("info"),
                                              Text.get("selection_info"),
                                              QtWidgets.QMessageBox.Ok,
                                              QtWidgets.QMessageBox.Ok)

    def extra_params_button_clicked(self, _):
        old_parameters = self.db.get_parameters()
        dialog = ExtraParametersDialog(old_parameters, self.settings)
        res = dialog.exec()
        if res == QtWidgets.QDialog.Accepted:
            new_parameters = dialog.get_parameters()
            self.db.set_parameters(new_parameters)
        dialog.close()

    def choose_download_path_button_clicked(self):
        new_path = QtWidgets.QFileDialog.getExistingDirectory(
            self, Text.get("download_folder"), self.settings.path)
        if new_path:
            self.ui.download_path_edit.setText(new_path)

    def choose_save_folder_path_button_clicked(self):
        new_path = QtWidgets.QFileDialog.getExistingDirectory(
            self, Text.get("save_folder"), self.settings.save_folder)
        if new_path:
            self.ui.save_folder_edit.setText(new_path)

    def russian_language_chosen(self):
        self.install_translator(Text.Lang.RU)
        self.settings.language = int(Text.Lang.RU)

    def english_language_chosen(self):
        self.install_translator(Text.Lang.EN)
        self.settings.language = int(Text.Lang.EN)

    def open_about(self):
        about_dialog = AboutDialog(self)
        about_dialog.exec()

    def closeEvent(self, a_event: QtGui.QCloseEvent):
        self.settings.save_qwidget_state(self.ui.measures_table)
        self.settings.save_qwidget_state(self.ui.mw_splitter_1)
        self.settings.save_qwidget_state(self)
        a_event.accept()
Пример #8
0
class MainWindow(QtWidgets.QMainWindow):
    clb_list_changed = QtCore.pyqtSignal([list])
    usb_status_changed = QtCore.pyqtSignal(clb.State)
    signal_enable_changed = QtCore.pyqtSignal(bool)

    def __init__(self):
        super().__init__()

        self.ui = MainForm()
        self.ui.setupUi(self)

        self.active_window = None

        try:
            self.settings = Settings(self)
            ini_ok = True
        except BadIniException:
            ini_ok = False
            QtWidgets.QMessageBox.critical(
                self, "Ошибка", 'Файл конфигурации поврежден. Пожалуйста, '
                'удалите файл "settings.ini" и запустите программу заново')
        if ini_ok:
            self.db_name = "measures.db"
            self.db_connection = MeasuresDB.create_db(self.db_name)
            self.show_start_window()
            self.show()

            self.clb_signal_off_timer = QtCore.QTimer()
            # noinspection PyTypeChecker
            self.clb_signal_off_timer.timeout.connect(self.close)
            self.SIGNAL_OFF_TIME_MS = 200

            self.clb_driver = clb_dll.set_up_driver(clb_dll.debug_dll_path)
            self.usb_driver = clb_dll.UsbDrv(self.clb_driver)
            self.usb_state = clb_dll.UsbDrv.UsbState.DISABLED
            self.calibrator = clb_dll.ClbDrv(self.clb_driver)
            self.clb_state = clb.State.DISCONNECTED

            self.usb_check_timer = QtCore.QTimer(self)
            self.usb_check_timer.timeout.connect(self.usb_tick)
            self.usb_check_timer.start(10)

            self.fast_config = None

            self.ui.enter_settings_action.triggered.connect(self.open_settings)

        else:
            self.close()

    def __del__(self):
        if hasattr(self, "display_db_connection"):
            self.db_connection.close()

    def usb_tick(self):
        self.usb_driver.tick()

        if self.usb_driver.is_dev_list_changed():
            self.clb_list_changed.emit(self.usb_driver.get_dev_list())

        if self.usb_driver.is_status_changed():
            self.usb_state = self.usb_driver.get_status()

        current_state = clb.State.DISCONNECTED
        if self.usb_state == clb_dll.UsbDrv.UsbState.CONNECTED:
            if self.calibrator.signal_enable_changed():
                self.signal_enable_changed.emit(self.calibrator.signal_enable)

            if not self.calibrator.signal_enable:
                current_state = clb.State.STOPPED
            elif not self.calibrator.is_signal_ready():
                current_state = clb.State.WAITING_SIGNAL
            else:
                current_state = clb.State.READY

        if self.clb_state != current_state:
            self.clb_state = current_state
            self.usb_status_changed.emit(self.clb_state)

    def close_active_window(self):
        self.hide()
        if self.active_window is not None:
            self.active_window.close()

    def show_start_window(self):
        try:
            self.close_active_window()

            self.active_window = StartWindow(self.db_connection, self.db_name,
                                             self.settings, self)
            self.setCentralWidget(self.active_window)
            self.active_window.source_mode_chosen.connect(
                self.open_source_mode_window)
            self.active_window.no_template_mode_chosen.connect(
                self.open_config_no_template_mode)
            self.active_window.template_mode_chosen.connect(
                self.template_mode_chosen)
            self.setWindowTitle(self.active_window.windowTitle())
        except Exception as err:
            utils.exception_handler(err)

    def attach_calibrator_to_window(self, a_window):
        assert hasattr(a_window,
                       "update_clb_list"), "no method update_clb_list"
        assert hasattr(a_window,
                       "update_clb_status"), "no method update_clb_status"

        self.clb_list_changed.connect(a_window.update_clb_list)
        self.clb_list_changed.emit(self.usb_driver.get_dev_list())

        self.usb_status_changed.connect(a_window.update_clb_status)
        self.usb_status_changed.emit(self.clb_state)

        self.signal_enable_changed.connect(a_window.signal_enable_changed)
        self.signal_enable_changed.emit(self.calibrator.signal_enable)

    def change_window(self, a_new_window):
        self.active_window = a_new_window
        self.attach_calibrator_to_window(self.active_window)

        self.setCentralWidget(self.active_window)
        self.setWindowTitle(self.active_window.windowTitle())

        self.active_window.close_confirmed.connect(self.close_child_widget)

    def open_source_mode_window(self):
        try:
            source_mode_dialog = SourceModeDialog(self.settings,
                                                  self.calibrator, self)
            self.attach_calibrator_to_window(source_mode_dialog)
            source_mode_dialog.exec()
        except Exception as err:
            utils.exception_handler(err)

    def open_config_no_template_mode(self):
        try:
            new_fast_measure_window = NewFastMeasureDialog(
                self.fast_config, self)
            new_fast_measure_window.config_ready.connect(
                self.save_no_template_config)

            if new_fast_measure_window.exec() == QtWidgets.QDialog.Accepted:
                assert self.fast_config is not None, "no_template_config must not be None!"
                new_fast_measure_window.close()
                self.start_fast_measure()
        except AssertionError as err:
            print(err)

    def save_no_template_config(self, a_config: FastMeasureParams):
        self.fast_config = a_config

    def start_fast_measure(self):
        try:
            measure_config = Measure.from_fast_params(self.fast_config)

            self.close_active_window()
            self.change_window(
                MeasureWindow(a_calibrator=self.calibrator,
                              a_measure_config=measure_config,
                              a_db_connection=self.db_connection,
                              a_settings=self.settings,
                              a_parent=self))
        except Exception as err:
            utils.exception_handler(err)

    def template_mode_chosen(self):
        try:
            template_list_dialog = TemplateListWindow(self.settings, self)
            template_list_dialog.config_ready.connect(
                self.start_template_measure)
            template_list_dialog.exec()
        except Exception as err:
            utils.exception_handler(err)

    def start_template_measure(self, a_template_params: TemplateParams,
                               a_variable_params: VariableTemplateParams):
        try:
            measure_config = Measure.from_template(a_template_params,
                                                   a_variable_params)

            self.close_active_window()
            self.change_window(
                MeasureWindow(a_calibrator=self.calibrator,
                              a_measure_config=measure_config,
                              a_db_connection=self.db_connection,
                              a_settings=self.settings,
                              a_parent=self))
        except Exception as err:
            utils.exception_handler(err)

    def close_child_widget(self):
        self.show_start_window()

    def open_settings(self):
        try:
            settings_dialog = SettingsDialog(self.settings, self.db_connection,
                                             self)
            settings_dialog.exec()
        except Exception as err:
            utils.exception_handler(err)

    def closeEvent(self, a_event: QtGui.QCloseEvent):
        try:
            if not isinstance(self.active_window, StartWindow):
                if hasattr(self.active_window, "ask_for_close"):
                    # Эмитит close_confirmed при подтверждении закрытия
                    self.active_window.ask_for_close()
                    a_event.ignore()
                else:
                    a_event.accept()
            else:
                if self.calibrator.signal_enable:
                    self.calibrator.signal_enable = False
                    self.clb_signal_off_timer.start(self.SIGNAL_OFF_TIME_MS)
                    a_event.ignore()
                else:
                    self.active_window.close()
                    a_event.accept()
        except Exception as err:
            print(err)