Пример #1
0
class PROCESS(QObject):
    queue_finished = pyqtSignal(int)
    prog_finished = pyqtSignal(tuple)
    stoped = pyqtSignal(int, int)  # 1: start, 0: finished, 2: error | queue
    state = pyqtSignal(int, str)

    def __init__(self, parent=None):
        QObject.__init__(self, parent)
        self.process = QProcess()
        self.process.setProcessChannelMode(QProcess.MergedChannels)
        self.process.finished.connect(self.emit_finished)
        self.process.stateChanged.connect(self.emit_state)
        self.process_type = 0  # 0 process, 1 runnable
        self.threadpool = QThreadPool()
        self.worker = Worker()
        self.worker.signals.state.connect(self.emit_state)
        self.queue = None

    def emit_state(self, state):
        self.state.emit(state, self.prog_name)

    def emit_finished(self, exitcode, exitstatus):
        self.prog_finished.emit((self.prog_name, exitcode, exitstatus))

    def set_queue(self, queue):
        self.queue = queue

    def start_process(self):
        try:
            obj = self.queue.get(False)
            self.prog_name = list(obj.keys())[0]
            if callable(list(obj.values())[0][0]):
                self.process_type = 1
                funct = list(obj.values())[0][0]
                args = list(obj.values())[0][1]
                self.worker.insert_function(funct, args, self.prog_name)
                self.threadpool.start(self.worker)
            else:
                self.process_type = 0
                self.process.start(
                    list(obj.values())[0][0],
                    list(obj.values())[0][1])
        except Empty:
            self.queue_finished.emit(self.queue.name)

    def force_finished(self):
        # for process (programs)
        self.stoped.emit(1, self.queue.name)
        if self.process_type == 0:
            self.process.terminate()
            if not self.process.waitForFinished(1000):
                self.process.kill()
        else:
            if self.threadpool.activeThreadCount():
                self.threadpool.clear()
                self.threadpool.waitForDone()
        with self.queue.mutex:
            self.queue.queue.clear()
        self.stoped.emit(0, self.queue.name)
Пример #2
0
class TaskConsumer(metaclass=SingletonMeta):
    def __init__(self) -> None:
        self.lock = threading.Lock()
        self.q = list()
        self.thread_pool = QThreadPool()
        self.thread_pool.setMaxThreadCount(1)

    def set_thread_pool(self, tp):
        self.thread_pool = tp

    def insert_task(self, task: Task) -> None:
        """
        Insert task if whether its not in queue or its status is either done or failed.
        :param task:
        :return:
        """
        with self.lock:
            self.__remove_finished_task()
            if not any(task.task_type == each.task_type for each in self.q):
                self.q.append(task)

    def get_task(self) -> Task:
        with self.lock:
            self.__remove_finished_task()
            if self.q:
                for each in self.q:
                    if each.task_type == TaskTypes.SERIAL_OPEN:
                        return each
                return self.q[0]
            else:
                return None

    def consume_task(self) -> None:
        task = self.get_task()
        if task and self.thread_pool.activeThreadCount() == 0:
            self.thread_pool.start(task)

    def clear_task_queue(self) -> None:
        self.q.clear()
        self.thread_pool.clear()

    def __remove_finished_task(self) -> None:
        clr_lst = [
            index for index, task in enumerate(self.q)
            if task.status > TaskStatus.RUNNING
        ]
        for index in clr_lst:
            del self.q[index]
Пример #3
0
class BackgroundWorker(QObject):
    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self._threads = QThreadPool()

    def runTask(self, fn=None, fn_started=None, fn_finished=None, fn_failed=None, token=None, fn_progress=None, **kwargs):
        self._threads.start(
            Task(
                fn=fn,
                fn_started=fn_started,
                fn_finished=fn_finished,
                fn_failed=fn_failed,
                cancel_token=token,
                fn_progress=fn_progress,
                **kwargs,
            )
        )

    def isRunning(self):
        return self._threads.activeThreadCount() > 0
Пример #4
0
class Fuzzer(QObject):
    communication = None

    def __init__(self, communication, max_thread_number, inputs, wordlist):
        super(Fuzzer, self).__init__()
        self.communication = communication
        self.max_thread_number = max_thread_number
        self.pool = QThreadPool()
        self.pool.globalInstance()
        self.inputs = inputs
        self.wordlist = wordlist
        self.socket_data = [inputs[0], inputs[1], inputs[2]]

    def start(self):
        num_of_chunks = len(self.wordlist) // int(self.max_thread_number)
        new_fuzz_list = list(self.listChunks(self.wordlist, num_of_chunks))

        self.pool.setMaxThreadCount(self.max_thread_number)

        for sub_list in new_fuzz_list:
            QCoreApplication.processEvents()
            for word in sub_list:
                QCoreApplication.processEvents()
                if self.pool.activeThreadCount() < self.pool.maxThreadCount():
                    fuzz_thread = Fuzz(self.communication,
                                       self.socket_data, self.inputs[3],
                                       str(word), self.inputs[5])
                    fuzz_thread.setAutoDelete(True)
                    self.pool.start(fuzz_thread)
                else:
                    self.pool.waitForDone()

    def __del__(self):
        pass

    def listChunks(self, myList, numOfChunks):
        for i in range(0, len(myList), numOfChunks):
            yield myList[i:i + numOfChunks]
Пример #5
0
class PackageMonitor(QThread):
    signal = pyqtSignal()

    def __init__(self):
        super().__init__()
        self.pool = QThreadPool()
        self.pool.globalInstance()
        self.pool.setMaxThreadCount(3)

    def run(self):
        flag = True
        while flag:
            count = self.pool.activeThreadCount()
            if count <= 0:  # 打包完成,发完成信号,重置flag,终止线程
                self.signal.emit()
                flag = False
            else:  # 打包进行中,线程休眠
                QThread.sleep(3)

    def add_runnable(self, runnable):
        self.pool.start(runnable)

    def clear(self):
        self.pool.clear()
Пример #6
0
class MainPage(QMainWindow):
    def __init__(self):
        super(MainPage, self).__init__()
        loadUi('./ui/ui_mainwindow.ui', self)
        self.mainapp = MainApp()  # main.py 에서 연결
        self.mainapp.gui_framework = self
        self.threadpool = QThreadPool()
        self._stopflag = False  # main app 정지 신호
        self._exitflag = False  # main app 종료 신호
        self.EXIT_CODE_REBOOT = -123456789

        # 초기 출력
        self.print_setting()  # mainwindow 의 textBrowser_setting 에 현재 설정 출력
        self.textBrowser.append("Multithreading with maximum %d threads" %
                                self.threadpool.maxThreadCount())

        # 시그널/슬롯 생성
        self.actionSimulationSetting.triggered.connect(
            self.executeConfigPage)  # 페이지(윈도우) 연결
        self.actionRun.triggered.connect(self.run_program)  # Run mainapp
        self.actionStop.triggered.connect(self.stop_program)
        # self.actionSaveAgent.triggered.connect(self.save_agent)
        self.actionLoadAgent.triggered.connect(self.load_agent)
        self.actionLoadAni.triggered.connect(self.load_animation)
        self.actionReboot.triggered.connect(self.reboot_program)

    def closeEvent(self, event):
        reply = QMessageBox.question(
            self, "Message",
            "Are you sure you want to quit? Any unsaved work will be lost.",
            QMessageBox.Close | QMessageBox.Cancel, QMessageBox.Cancel)

        if reply == QMessageBox.Close:
            self._stopflag = True
            self._exitflag = True
            event.accept()
        else:
            event.ignore()

    def run_program(self):
        worker = Worker(self.mainapp)
        # 정지설정 False / run & 설정버튼 비활성화
        self._stopflag = False
        self.actionRun.setEnabled(False)
        self.actionSimulationSetting.setEnabled(False)
        # Execute
        self.threadpool.start(worker)
        self.write_console("Multithreading with %d of %d threads" %
                           (self.threadpool.activeThreadCount(),
                            self.threadpool.maxThreadCount()))

        # Alternative: def run_program2(self):  # 외부에서 self.actionRun.triggered.connect(self.run_program2)        #
        #     self.thread = Thread(target=self.mainapp.run_main)
        #     self.thread.daemon = True
        #     self.thread.start()

    def stop_program(self):
        self._stopflag = True
        self.actionRun.setEnabled(True)
        self.actionSimulationSetting.setEnabled(True)

    def reboot_program(self):
        reply = QMessageBox.question(
            self, "Message",
            "Are you sure you want to reboot? Any unsaved work will be lost.",
            QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Cancel)
        if reply == QMessageBox.Ok:
            self._stopflag = True
            self._exitflag = True
            qApp.exit(self.EXIT_CODE_REBOOT)

    # def save_agent(self):
    #     if not self.mainapp.env:
    #         QMessageBox.warning(self, "Message", "Any agent/environment isn't loaded.")
    #     elif self.mainapp.agent.name == 'rl':
    #         self.mainapp.agent.save_file(self.mainapp.log_dir, self.mainapp.iter)
    #         QMessageBox.information(self, "Message", "RL agent file is saved")
    #     elif self.mainapp.agent.name == 'greedy':
    #         QMessageBox.warning(self, "Message", "Greedy agent file CANNOT be saved")

    def load_agent(self):
        options = QFileDialog.Options()
        # filter: "All Files (*)", "Python Files (*.py)", "PKL Files (*.pkl)"
        fileName, _ = QFileDialog.getOpenFileName(
            self,
            "QFileDialog.getOpenFileName()",
            "",
            "PKL Files (*.pkl)",
            options=options)
        if fileName:
            QMessageBox.information(self, "Message",
                                    "agent file is loaded \n %s" % fileName)
            self.mainapp.agent_name = fileName
            self.print_setting()

    def load_animation(self):
        options = QFileDialog.Options()
        # filter: "All Files (*)", "Python Files (*.py)", "PKL Files (*.pkl)"
        fileName, _ = QFileDialog.getOpenFileName(
            self,
            "QFileDialog.getOpenFileName()",
            "",
            "PKL Files (*.pkl)",
            options=options)
        if fileName:
            QMessageBox.information(
                self, "Message", "animation file is loaded \n %s" % fileName)
            with open(fileName,
                      'rb') as file:  # james.p 파일을 바이너리 읽기 모드(rb)로 열기
                ani_data = pickle.load(file)
            temp_ani = GraphicDisplay(ani_data['width'],
                                      ani_data['height'],
                                      unit_pixel=ani_data['unit'])
            temp_ani.data = ani_data['data']
            temp_ani.mainloop()

    def print_setting(self):
        self.textBrowser_setting.setText("[ Current Setting ]\n")
        if self.mainapp.agent_name.lower() in ('rl', 'reinforcement learning'):
            self.textBrowser_setting.append("Agent: Reinforcement Learning")
        elif self.mainapp.agent_name.lower() == 'greedy':
            self.textBrowser_setting.append("Agent: %s" %
                                            self.mainapp.agent_name)
        else:
            self.textBrowser_setting.append("Agent: Loaded %s" %
                                            self.mainapp.agent_name)
        self.textBrowser_setting.append("Task: %s" % self.mainapp.task)
        self.textBrowser_setting.append("Num Battery: %d" % self.mainapp.b_num)
        self.textBrowser_setting.append("Num Flight: %d" % self.mainapp.f_num)
        self.textBrowser_setting.append("Flight Time Interval: %.2f" %
                                        self.mainapp.f_interval)
        self.textBrowser_setting.append("Defense range (map width): %.2f" %
                                        self.mainapp.map_width)
        self.textBrowser_setting.append("Termination Type: %s" %
                                        str(self.mainapp.termination[0]))
        self.textBrowser_setting.append("Termination Criteria: %s" %
                                        str(self.mainapp.termination[1]))
        self.textBrowser_setting.append("Autosave cycle: %d iter" %
                                        self.mainapp.autosave_iter)

    def executeConfigPage(self):
        simconfig_page = SimconfigPage(self, self.mainapp)
        simconfig_page.exec_()

    def write_console(self, text, box='textBrowser'):
        if box == 'textBrowser_setting':
            self.textBrowser_setting.append(str(text))
            self.textBrowser_setting.moveCursor(QtGui.QTextCursor.End)
        else:
            self.textBrowser.append(str(text))
            self.textBrowser.moveCursor(QtGui.QTextCursor.End)
Пример #7
0
class Main_Window_class(QDialog):
    PLOTS_NUMBER = 3
    EFFECTS_NUMBER = 4

    def __init__(self):
        super().__init__()
        self.nlabels = 6

        self.slider_step = 1
        self.slider_default = 0
        self.slider_max = 50
        self.slider_min = -50

        # Коэффициент ослабления эхо эффекта
        self.echo_coefficient = 1
        # Задержка в фреймах
        self.echo_shift = 1000

        # "Жесткий" предел овердрайва за которым волна обрезается
        self.soft_clipping_hard_limit = 14000
        # "Мягкий" предел овердрайва за которым волна сглаживается
        self.soft_clipping_linear_limit = 12000  # -3 dB

        self.music_is_playing = False
        self.threadpool = QThreadPool()
        self.nchannels = None  # number of channels
        self.sampwidth = None  # number of bytes per sample
        self.framerate = None  # number of frames per second
        self.nframes = None  # total number of frames
        self.comptype = None  # compression type
        self.compname = None  # compression type name
        self.elem_per_hertz = None
        self.coefficient = 1000  # коэффициент прореживания, для уменьшения частоты дискретизации
        self.buffer_size = None
        self.buffer_cnt = 0
        self.music_worker = None
        self.min_freq = 0
        self.max_freq = None

        self.channels = []
        self.spectrum = None

        self.spectrum_original = None
        self.channels_original = []

        self.spectrum_hard_clipping = None
        self.channels_hard_clipping = []

        self.spectrum_soft_clipping = None
        self.channels_soft_clipping = None

        self.spectrum_envelop = None
        self.channels_envelop = []

        self.spectrum_echo = None
        self.channels_echo = []

        self.app_name = 'Эквалайзер'
        self.buttons_labels = ['Воспроизвести', 'Пауза', 'Остановить']
        self.bands = [[], []]
        self.labels = []
        self.ui_labels = []
        self.sliders = []
        self.sliders_workers = [None for _ in range(self.nlabels)]
        self.sliders_old_values = [
            self.slider_default for _ in range(self.nlabels)
        ]
        self.LCD_numbers = []
        self.canvases = []
        self.effects = [
            self.doing_hard_clipping, self.doing_envelop, self.doing_echo,
            self.doing_soft_clipping
        ]
        self.effects_checkboxes_labels = [
            'Жесткий клиппинг (дисторшн)', 'Энвелоп', 'Эхо',
            'Мягкий клиппинг (овердрайв)'
        ]
        self.effects_checkboxes = []
        self.effects_checkboxes_workers = []
        self.play_button, self.stop_button, self.pause_button = None, None, None
        self.redraw_mutex = threading.Lock()

        self.run_ui()

    def run_ui(self):
        self.pull_music()
        self.create_interface()

    def pull_music(self):
        path_to_pull = QFileDialog.getOpenFileName(self,
                                                   'Выберите .wav файл')[0]
        wav = wave.open(path_to_pull, mode='r')

        # nchannels - число каналов .wav файла
        # sampwidth - число байт на сэмпл
        # framerate - число фреймов в секунду
        # nframes - общее число фреймов
        # comptype - тип сжатия
        # compname - имя типа сжатия
        (self.nchannels, self.sampwidth, self.framerate, self.nframes,
         self.comptype, self.compname) = wav.getparams()

        # Теорема Котельникова, в дискретном сигнале представлены частоты от нуля до framerate // 2
        self.max_freq = self.framerate // 2
        self.buffer_size = self.framerate

        # считываем все фреймы
        content = wav.readframes(self.nframes)

        # и сохраняем в массив с нужным типом элемента
        samples = np.fromstring(content, dtype=IntTypes.types[self.sampwidth])

        # разбиваем на каналы, например, \xe2\xff\xe3\xfа — это фрейм 16-битного wav-файла. Значит, \xe2\xff — сэмпл
        # первого (левого) канала, а \xe3\xfа
        for i in range(self.nchannels):
            self.channels.append(samples[i::self.nchannels])

        # сохраняем оригинальные каналы
        self.channels_original = self.channels.copy()

        # создаем worker'ов, который создадут измененные дорожки с примененными эффектами

        for i in range(self.EFFECTS_NUMBER):
            worker = Worker(self.effects[i], self.channels)
            self.effects_checkboxes_workers.append(worker)
            self.threadpool.start(worker)

        # Выполняем быстрое дискретное преобразование Фурье, для получения спектра
        self.spectrum = np.fft.rfft(self.channels_original)
        self.spectrum_original = self.spectrum.copy()

        # запускаем pygame
        pygame.mixer.pre_init(frequency=self.framerate,
                              size=-8 * self.sampwidth,
                              channels=self.nchannels)
        pygame.init()

    def create_bands(self):
        """Создает подписи к слайдерам"""
        step = (self.max_freq - self.min_freq) // 2**self.nlabels

        self.bands[0].append(self.min_freq)
        self.bands[1].append(self.min_freq + step)

        for i in range(1, self.nlabels - 1):
            self.bands[0].append(self.bands[1][i - 1])
            self.bands[1].append(self.bands[0][i] + 2**i * step)

        self.bands[0].append(self.bands[1][self.nlabels - 2])
        self.bands[1].append(self.max_freq)

        for i in range(self.nlabels):
            self.labels.append(f'{self.bands[0][i]} - {str(self.bands[1][i])}')

    def create_labels(self):
        for label in self.labels:
            self.ui_labels.append(QLabel(label, self))

    def create_lcd_numbers(self):
        for _ in range(self.nlabels):
            self.LCD_numbers.append(QLCDNumber(self))

    def create_sliders(self):
        for i in range(self.nlabels):
            slider = QSlider(Qt.Vertical, self)
            slider.setMinimum(self.slider_min)
            slider.setMaximum(self.slider_max)
            slider.setValue(self.slider_default)
            slider.setFocusPolicy(Qt.StrongFocus)
            slider.setTickPosition(QSlider.TicksBothSides)
            slider.setSingleStep(self.slider_step)
            slider.valueChanged[int].connect(self.slider_change_value)
            slider.valueChanged[int].connect(self.LCD_numbers[i].display)
            self.sliders.append(slider)

    def create_checkboxes(self):
        for i in range(self.EFFECTS_NUMBER):
            checkbox = QCheckBox(self.effects_checkboxes_labels[i], self)
            checkbox.setChecked(False)
            checkbox.stateChanged.connect(self.checkbox_clicked_listener)
            self.effects_checkboxes.append(checkbox)

    def create_buttons(self):
        self.play_button = QPushButton(self.buttons_labels[0], self)
        self.pause_button = QPushButton(self.buttons_labels[1], self)
        self.stop_button = QPushButton(self.buttons_labels[2], self)

        self.play_button.clicked.connect(self.button_clicked_listener)
        self.pause_button.clicked.connect(self.button_clicked_listener)
        self.stop_button.clicked.connect(self.button_clicked_listener)

    def create_graphics(self):
        self.create_lcd_numbers()
        self.create_sliders()
        self.create_bands()
        self.create_labels()
        self.create_checkboxes()
        self.create_buttons()

        self.elem_per_hertz = self.spectrum.shape[1] // (self.max_freq -
                                                         self.min_freq)
        plots_labels = [('Частота, Гц', 'Амплитуда'),
                        ('Частота, Гц', 'Амплитуда'),
                        ('Время, с', 'Амплитуда')]
        plots_sources = [
            (self.channels[0][::self.coefficient], ),
            (np.fft.rfftfreq(self.nframes,
                             1. / self.framerate)[::self.coefficient],
             np.abs(self.spectrum[0][::self.coefficient]) / self.nframes),
            (np.fft.rfftfreq(self.nframes,
                             1. / self.framerate)[::self.coefficient],
             np.abs(self.spectrum[0][::self.coefficient]) / self.nframes)
        ]
        for i in range(self.PLOTS_NUMBER):
            figure = plt.figure()
            subplot = figure.add_subplot(1, 1, 1)
            subplot.plot(*plots_sources[i])
            subplot.set_xlabel(plots_labels[i][0])
            subplot.set_ylabel(plots_labels[i][1])
            figure.align_xlabels()
            figure.align_ylabels()
            canvas = FigureCanvas(figure)
            navigation_tool = NavigationToolbar(canvas, self)
            canvas = {
                'figure': figure,
                'canvas': canvas,
                'navigation_tool': navigation_tool,
                'axes_labels': plots_labels[i],
            }
            self.canvases.append(canvas)
            canvas['canvas'].draw()

    def create_interface(self):
        self.create_graphics()
        labels_box = QHBoxLayout()
        for label in self.ui_labels:
            labels_box.addWidget(label)

        nums_box = QHBoxLayout()
        for number in self.LCD_numbers:
            nums_box.addWidget(number)

        sliders_box = QHBoxLayout()
        for slider in self.sliders:
            sliders_box.addWidget(slider)

        graph_box = QVBoxLayout()
        graph_box.addWidget(self.canvases[0]['navigation_tool'])
        graph_box.addWidget(self.canvases[0]['canvas'])

        left_box = QVBoxLayout()
        left_box.addLayout(labels_box)
        left_box.addLayout(sliders_box)
        left_box.addLayout(nums_box)
        left_box.addLayout(graph_box)

        checkbox_and_button_layout = QHBoxLayout()
        for i in range(self.EFFECTS_NUMBER):
            checkbox_and_button_layout.addWidget(self.effects_checkboxes[i])
        checkbox_and_button_layout.addWidget(self.play_button)
        checkbox_and_button_layout.addWidget(self.pause_button)
        checkbox_and_button_layout.addWidget(self.stop_button)

        graph_box = QVBoxLayout()
        graph_box.addWidget(self.canvases[1]['navigation_tool'])
        graph_box.addWidget(self.canvases[1]['canvas'])
        graph_box.addWidget(self.canvases[2]['navigation_tool'])
        graph_box.addWidget(self.canvases[2]['canvas'])

        right_box = QVBoxLayout()
        right_box.addLayout(checkbox_and_button_layout)
        right_box.addLayout(graph_box)

        all_box = QHBoxLayout()
        all_box.addLayout(left_box)
        all_box.addLayout(right_box)

        self.setLayout(all_box)

        self.setWindowTitle(self.app_name)
        self.showMaximized()

    def slider_change_value(self, value):
        for i, slider in enumerate(self.sliders):
            if self.sender() == slider:
                self.sliders_workers[i] = Worker(self.music_edit, i, value)
                self.threadpool.start(self.sliders_workers[i])

    def checkbox_clicked_listener(self, state):
        if self.sender() == self.effects_checkboxes[0]:
            if state == Qt.Checked:
                self.effects_checkboxes[1].setChecked(False)
                self.effects_checkboxes[2].setChecked(False)
                self.effects_checkboxes[3].setChecked(False)
                self.channels = self.channels_hard_clipping.copy()
                self.spectrum = self.spectrum_hard_clipping.copy()
            else:
                self.channels = self.channels_original.copy()
                self.spectrum = self.spectrum_original.copy()

        elif self.sender() == self.effects_checkboxes[1]:
            if state == Qt.Checked:
                self.effects_checkboxes[0].setChecked(False)
                self.effects_checkboxes[2].setChecked(False)
                self.effects_checkboxes[3].setChecked(False)
                self.channels = self.channels_envelop.copy()
                self.spectrum = self.spectrum_envelop.copy()
            else:
                self.channels = self.channels_original.copy()
                self.spectrum = self.spectrum_original.copy()

        elif self.sender() == self.effects_checkboxes[2]:
            if state == Qt.Checked:
                self.effects_checkboxes[0].setChecked(False)
                self.effects_checkboxes[1].setChecked(False)
                self.effects_checkboxes[3].setChecked(False)
                self.channels = self.channels_echo.copy()
                self.spectrum = self.spectrum_echo.copy()
            else:
                self.channels = self.channels_original.copy()
                self.spectrum = self.spectrum_original.copy()

        elif self.sender() == self.effects_checkboxes[3]:
            if state == Qt.Checked:
                self.effects_checkboxes[0].setChecked(False)
                self.effects_checkboxes[1].setChecked(False)
                self.effects_checkboxes[2].setChecked(False)
                self.channels = self.channels_soft_clipping.copy()
                self.spectrum = self.spectrum_soft_clipping.copy()
            else:
                self.channels = self.channels_original.copy()
                self.spectrum = self.spectrum_original.copy()

        for slider in self.sliders:
            slider.setValue(self.slider_default)

        draw_1 = Worker(self.draw_array, self.spectrum, 0)
        self.threadpool.start(draw_1)

        draw_2 = Worker(self.draw_array, self.channels, 1)
        self.threadpool.start(draw_2)

    def button_clicked_listener(self):
        if self.sender() == self.play_button:
            # Запустить
            if not self.music_is_playing:
                self.music_is_playing = True
                self.music_worker = Worker(self.start_music)
                self.threadpool.start(self.music_worker)

        elif self.sender() == self.pause_button:
            # Пауза
            if self.music_is_playing:
                self.music_is_playing = False

        elif self.sender() == self.stop_button:
            # Остановить
            if self.music_is_playing:
                self.music_is_playing = False

            self.threadpool.clear()

            for slider in self.sliders:
                worker = Worker(self.music_edit, self.sliders.index(slider),
                                self.slider_default)
                self.sliders_workers.append(worker)
                self.threadpool.start(worker)

            self.threadpool.start(Worker(self.wait_until_sliders_launched))

            for slider in self.sliders:
                slider.setValue(self.slider_default)

            self.buffer_cnt = 0

            for i in range(self.EFFECTS_NUMBER):
                self.effects_checkboxes[i].setChecked(False)

    def wait_until_sliders_launched(self):
        while self.threadpool.activeThreadCount() != len(self.sliders):
            sleep(0.1)
        self.channels = self.channels_original.copy()
        self.spectrum = self.spectrum_original.copy()

    def start_music(self):
        tmp_channels = [
            self.channels[0][self.buffer_cnt *
                             self.buffer_size:(self.buffer_cnt + 1) *
                             self.buffer_size + 1:],
            self.channels[1][self.buffer_cnt *
                             self.buffer_size:(self.buffer_cnt + 1) *
                             self.buffer_size + 1:]
        ]
        tmp_channels = np.array(tmp_channels)
        tmp_channels = np.ascontiguousarray(tmp_channels.T)
        tmp_sound = pygame.sndarray.make_sound(tmp_channels)

        sound = tmp_sound
        if not self.music_is_playing:
            return
        pygame.mixer.Sound.play(sound)

        start_pos = self.buffer_cnt
        for self.buffer_cnt in range(start_pos + 1,
                                     self.nframes // self.buffer_size):
            tmp_channels = [
                self.channels[0][self.buffer_cnt *
                                 self.buffer_size:(self.buffer_cnt + 1) *
                                 self.buffer_size + 1:],
                self.channels[1][self.buffer_cnt *
                                 self.buffer_size:(self.buffer_cnt + 1) *
                                 self.buffer_size + 1:]
            ]
            tmp_channels = np.array(tmp_channels)
            tmp_channels = np.ascontiguousarray(tmp_channels.T)
            tmp_sound = pygame.sndarray.make_sound(tmp_channels)

            while pygame.mixer.get_busy():
                sleep(0.01)

            sound = tmp_sound
            if not self.music_is_playing:
                return
            pygame.mixer.Sound.play(sound)

        tmp_channels = [
            self.channels[0][self.buffer_cnt * self.buffer_size::],
            self.channels[1][self.buffer_cnt * self.buffer_size::]
        ]
        tmp_channels = np.array(tmp_channels)
        tmp_channels = np.ascontiguousarray(tmp_channels.T)
        tmp_sound = pygame.sndarray.make_sound(tmp_channels)

        while pygame.mixer.get_busy():
            sleep(0.01)

        sound = tmp_sound
        if not self.music_is_playing:
            return
        pygame.mixer.Sound.play(sound)

        self.buffer_cnt = 0
        self.music_is_playing = False

    def music_edit(self, pos, value):
        old_value = self.sliders_old_values[pos]
        self.sliders_old_values[pos] = value

        if old_value == value:
            return

        if pos == 0:
            for i in range(self.nchannels):
                self.spectrum[i][:self.elem_per_hertz * self.bands[1][pos] +
                                 1] *= 10**((value - old_value) / 20)

        elif pos == 5:
            for i in range(self.nchannels):
                self.spectrum[i][self.elem_per_hertz *
                                 self.bands[0][pos]:] *= 10**(
                                     (value - old_value) / 20)

        else:
            for i in range(self.nchannels):
                self.spectrum[i][self.elem_per_hertz *
                                 self.bands[0][pos]:self.elem_per_hertz *
                                 self.bands[1][pos] +
                                 1] *= 10**((value - old_value) / 20)

        self.channels = (np.fft.irfft(self.spectrum)).astype(
            IntTypes.types[self.sampwidth])

        draw_1 = Worker(self.draw_array, self.spectrum, 0)
        self.threadpool.start(draw_1)

        draw_2 = Worker(self.draw_array, self.channels, 1)
        self.threadpool.start(draw_2)

    def redraw_subplot(self, canvas: dict, left, right=None):
        # потоконебезопасная функция, нужен mutex
        self.redraw_mutex.acquire()
        canvas['figure'].clear()
        subplot = canvas['figure'].add_subplot(1, 1, 1)
        subplot.set_xlabel(canvas['axes_labels'][0])
        subplot.set_ylabel(canvas['axes_labels'][1])
        canvas['figure'].align_xlabels()
        canvas['figure'].align_ylabels()
        if right is not None:
            subplot.plot(left, right)
        else:
            subplot.plot(left)
        canvas['canvas'].draw()
        self.redraw_mutex.release()

    def draw_array(self, arr, spectrum_or_channel):
        if spectrum_or_channel == 0:
            self.redraw_subplot(
                self.canvases[1],
                np.fft.rfftfreq(self.nframes,
                                1. / self.framerate)[::self.coefficient],
                np.abs(arr[0][::self.coefficient]) / self.nframes)
        else:
            self.redraw_subplot(self.canvases[0], arr[0][::self.coefficient])

    def doing_hard_clipping(self, channels):
        threshold_max = int(0.6 * np.max(channels[0]))
        threshold_min = int(0.6 * np.min(channels[0]))

        self.channels_hard_clipping = np.maximum(
            np.minimum(channels, threshold_max),
            threshold_min).astype(IntTypes.types[self.sampwidth])
        self.spectrum_hard_clipping = np.fft.rfft(self.channels_hard_clipping)

    def doing_soft_clipping(self, channels):
        clip_limit = self.soft_clipping_linear_limit + int(
            pi / 2 *
            (self.soft_clipping_hard_limit - self.soft_clipping_linear_limit))
        scale = self.soft_clipping_hard_limit - self.soft_clipping_linear_limit

        tmp_channels = np.array(channels, copy=True)
        for i in range(len(tmp_channels)):
            for j in range(len(tmp_channels[i])):
                n = tmp_channels[i][j]
                amplitude, sign = abs(n), 1 if n >= 0 else -1
                if amplitude <= self.soft_clipping_linear_limit:
                    tmp_channels[i][j] = n
                    continue
                if amplitude >= clip_limit:
                    tmp_channels[i][j] = self.soft_clipping_hard_limit * sign
                    continue
                compression = scale * sin(
                    float(amplitude - self.soft_clipping_linear_limit) / scale)
                tmp_channels[i][j] = (self.soft_clipping_linear_limit +
                                      int(compression)) * sign

        self.channels_soft_clipping = tmp_channels
        self.spectrum_soft_clipping = np.fft.rfft(self.channels_soft_clipping)

    def doing_envelop(self, channels):
        frequency = 1 / 15
        envelope_sig = np.array([
            abs(sin(2 * pi * frequency * t / self.framerate))
            for t in range(self.nframes)
        ])
        tmp_channels = np.array(channels, copy=True)

        for i in range(self.nchannels):
            tmp_channels[i] = (tmp_channels[i] * envelope_sig).astype(
                IntTypes.types[self.sampwidth])

        self.channels_envelop = tmp_channels
        self.spectrum_envelop = np.fft.rfft(self.channels_envelop)

    def doing_echo(self, channels):
        tmp_channels = np.array(channels, copy=True)
        echo_channels = tmp_channels.copy()
        for i in range(len(tmp_channels)):
            echo_channels[i] = (echo_channels[i] *
                                self.echo_coefficient).astype(
                                    IntTypes.types[self.sampwidth])
            echo_channels[i] = np.append(echo_channels[i][self.echo_shift:],
                                         np.zeros(self.echo_shift)).astype(
                                             IntTypes.types[self.sampwidth])
            tmp_channels[i] += echo_channels[i]

        self.channels_echo = tmp_channels
        self.spectrum_echo = np.fft.rfft(self.channels_echo)
Пример #8
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.mode = ['lineart', 'gray', 'color']
        self.resolution = ['75', '100', '150', '200', '300', '600', '1200']
        self.compression = ['None', 'JPEG']
        self.scanFolder = os.getcwd()
        self.ver = sane.init()

        self.ui = uic.loadUi("mainwindow.ui", self)
        #self.ui = Ui_MainWindow()
        #self.ui.setupUi(self)

        self.dialog = QDialog()
        self.message = QMessageBox()

        self.threadpool = QThreadPool()

        self.settings = QSettings("bibuweb.de", "Scan2Folder")

        self.progressBar = None

        self.configWin = ConfigWindow(self)
        self.configWin.ui.scanButton.clicked.connect(self.configScan)

        self.ui.resolutions.addItems(self.resolution)
        self.ui.resolutions.setCurrentIndex(
            self.ui.resolutions.findText('300'))

        self.ui.btnOpenDir.clicked.connect(self.openDir)
        self.ui.btnStartscan.clicked.connect(self.startScanJob)
        self.ui.btnOcr.clicked.connect(self.ocr_startProcess)

        self.ui.actionCalibrate.triggered.connect(self.configureWindow)
        self.configWin.ui.saveButton.clicked.connect(self.saveConfig)

        # Change Color back after error
        self.ui.filename.cursorPositionChanged.connect(self.leditcolor)

        self.ui.scanpath.cursorPositionChanged.connect(self.leditcolor)
        self.ui.scanpath.textChanged.connect(self.scanPathCanged)

        self.is_dev = True
        self.dev_available = False
        self.dev_connected = False
        self.adf = False
        self.dev = None
        self.devices = []
        self.scanStatus = False
        self.btnStyle = ""

        self.contrast = 1
        self.brightness = 1
        self.color = 1
        self.sharpness = 1
        self.scanPath = ""
        self.ocr = False
        self.crop = False
        self.cropSize = {'left': 1, 'top': 1, 'width': 1, 'height': 1}
        self.ocrFiles = []
        self.tempocr = None

        if self.settings.contains("ocr"):
            print("Load: ", self.settings.value('ocr'))
            if self.settings.value('ocr') == 'true':
                self.ocr = True
                self.ui.actionEnable_OCR.setChecked(True)
                self.configWin.ui.OCR_Enabled.setChecked(True)
                self.configWin.ui.OCR_Box.setEnabled(True)

            else:
                self.ui.actionEnable_OCR.setChecked(False)
                self.configWin.ui.OCR_Enabled.setChecked(False)
                self.configWin.ui.OCR_Box.setEnabled(False)
            ## connect Signal here and not before loading settings
            ## if not, you never will get the stored value because QAction is triggered when ever the value changed
            self.configWin.ui.OCR_Enabled.stateChanged.connect(self.ocrConfig)

        if self.settings.contains('crop'):
            if self.settings.value('crop') == 'true':
                self.crop = True
            self.configWin.ui.checkCrop.setChecked(self.crop)

        if self.settings.contains('cropSize'):
            #print(self.settings.value('cropSize'))
            self.cropSize = self.settings.value('cropSize')
            self.configWin.ui.cropX.setValue(self.cropSize['left'])
            self.configWin.ui.cropY.setValue(self.cropSize['top'])
            self.configWin.ui.cropW.setValue(self.cropSize['width'])
            self.configWin.ui.cropH.setValue(self.cropSize['height'])

        if self.settings.contains("path"):
            self.ui.scanpath.setText(self.settings.value("path"))
            self.scanPath = self.settings.value("path")
            self.createCompleter()

        if self.settings.contains('contrast'):
            self.brightness = self.settings.value('brightness')

            self.contrast = self.settings.value('contrast')
            self.configWin.ui.brigthnessLcd.setValue(float(self.brightness))
            self.configWin.ui.brigthnesSlider.setValue(
                int(float(self.brightness) * 10))
            self.configWin.ui.contrastLcd.setValue(float(self.contrast))
            self.configWin.ui.contrastSlider.setValue(
                int(float(self.contrast) * 10))

        if self.settings.contains('color'):
            self.color = self.settings.value('color')
            self.configWin.ui.colorLcd.setValue(float(self.color))
            self.configWin.ui.colorSlider.setValue(int(float(self.color) * 10))

        if self.settings.contains("sharpness"):
            self.sharpness = self.settings.value('sharpness')
            self.configWin.ui.sharpnessLcd.setValue(float(self.sharpness))
            self.configWin.ui.sharpnessSlider.setValue(
                int(float(self.sharpness) * 10))

    def closeEvent(self, event):
        #if not set, process keeps running in background
        self.scanStatus = False

    def openDir(self):
        fileDlg = QFileDialog()
        self.scanFolder = fileDlg.getExistingDirectory(
            self, 'Scan Folder', self.scanFolder,
            QFileDialog.DontUseNativeDialog)
        self.ui.scanpath.setText(self.scanFolder)
        self.settings.setValue("path", self.scanFolder)
        self.settings.sync()

    def startThread(self, fn, resultFn=None, complete=None):
        worker = Worker(
            fn)  # Any other args, kwargs are passed to the run function
        if resultFn is not None:
            worker.signals.result.connect(resultFn)
        if complete is not None:
            worker.signals.finished.connect(complete)
        #worker.signals.progress.connect(self.scannerProgress)
        self.threadpool.start(worker)

    def thread_complete(self):
        self.scannerProgress(100)
        time.sleep(1)
        self.dialog.close()

        if self.dev_available:
            self.show()
        else:
            #TODO: put error dlg here
            self.message.setText(
                "No scanner found\n Check your Configuration!")
            self.message.exec()
            print("Error: No Devices found")

        print("THREAD COMPLETE! ", self.threadpool.activeThreadCount())

    @pyqtSlot(str)
    def scanPathCanged(self, path):
        self.scanPath = path
        self.createCompleter()

    def createCompleter(self):
        ff = glob.glob(self.scanPath + "/*.pdf")
        files = []
        for f in ff:
            files.append(os.path.basename(f).split('.')[0])
        completer = QCompleter(files)
        completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.ui.filename.setCompleter(completer)

    def scannerLookup(self):

        #self.dialog.setModal(True)

        self.uidlg = Ui_Dialog()
        self.uidlg.setupUi(self.dialog)

        self.dialog.show()

    def checkScanMode(self):
        mode = ""
        if self.ui.btnBuW.isChecked():
            mode = self.ui.btnBuW.text()
        elif self.ui.btnGray.isChecked():
            mode = self.ui.btnGray.text()
        elif self.ui.btnColor.isChecked():
            mode = self.ui.btnColor.text()
        print(mode)
        return mode

    def scannerAddToDlg(self, result):
        self.devices = result
        if len(self.devices) > 0:
            self.dev_available = True
            for i, dev in enumerate(result):
                self.ui.comboBox.addItem(dev[i])
        else:
            return

    def scannerProgress(self, val):
        self.uidlg.progressBar.setValue(val)

    def scanners(self):
        self.scannerLookup()
        self.startThread(sane.get_devices, self.scannerAddToDlg,
                         self.thread_complete)

    def scannerCheck(self):
        self.statusBar().showMessage("looking up for scanner ....")
        print(self.devices[0])
        count = 0
        while self.is_dev:

            try:
                #ToDo: check index from

                self.dev = sane.open(self.devices[0][0])

            except:
                print("no scanner connected, waiting...", self.dev)
            if self.dev is not None:
                self.is_dev = False
                self.dev_connected = True
                print("scanner connected")
            time.sleep(3)
            ## Stop process after 3 times to avoid endless loop if no device is available
            ## due started as thread
            count += 1
            if count > 2:
                self.is_dev = False
                self.statusBar().showMessage("No Scanner connected!")

    def commonThreadEnd(self):
        print("Thread ended")

    def scanDocThreadEnded(self):
        self.statusBar().showMessage("Job stopped")
        self.scanStatus = False
        self.setLedStatus()

    def scannerCheckThreadEnd(self):
        print("Lookup Thread ended")

        if self.dev_connected:
            self.startThread(self.scanDocuments, None, self.scanDocThreadEnded)

    def setScannerStatus(self):
        if self.dev_connected:
            self.setLedStatus()
            self.statusBar().showMessage("Scanner connected", 10)
            self.setScanButton("running")
        else:
            self.setScanButton('stopped')

    def setLedStatus(self):
        if self.scanStatus:
            pix = QPixmap(":/images/square_green.svg")
        else:
            pix = QPixmap(":/images/square_red.svg")

        self.ui.statusLed.setPixmap(pix)

    def scanDocuments(self):
        ip = self.devices[0][0].split('=')[1]
        print(ip)
        url = 'http://' + ip + XML_PATH
        self.dev.mode = self.checkScanMode()
        self.dev.resolution = int(self.ui.resolutions.currentText())
        imgNr = 0
        savePath = self.ui.scanpath.text() + "/"
        imgPrefix = self.ui.filename.text() + "_"
        #self.dev.contrast = 900
        #self.dev.brightness = self.brightness
        while self.scanStatus:
            btnreq = urlopen(url)
            soup = bs4.BeautifulSoup(str(btnreq.read()), 'lxml')
            if soup.startscan.string == str(1):
                #print("Pressed")
                if soup.adfloaded.string == str(1):
                    self.adf = True
                    print("ADF Source")
                    self.dev.source = 'ADF'
                    imIter = self.dev.multi_scan()

                    while self.adf:
                        try:
                            im = imIter.next()
                            imgNr = imgNr + 1
                            img = imgPrefix + str(imgNr) + ".png"
                            im.save(savePath + img)
                            if self.ocr:
                                self.ocrFiles.append(savePath + img)
                        except:
                            self.adf = False
                            break
                else:
                    self.adf = False
                    imgNr = imgNr + 1
                    img = imgPrefix + str(imgNr) + ".png"
                    self.dev.start()
                    im = self.dev.snap()
                    self.enhanceImage(im, savePath, img)
                    if self.ocr:
                        self.ocrFiles.append(savePath + img)
            time.sleep(3)

    def enhanceImage(self, image, path, pf):
        brightness = ImageEnhance.Brightness(image)
        image = brightness.enhance(float(self.brightness))
        contrast = ImageEnhance.Contrast(image)
        image = contrast.enhance(float(self.contrast))
        colour = ImageEnhance.Color(image)
        image = colour.enhance(float(self.color))
        sharpness = ImageEnhance.Sharpness(image)
        image = sharpness.enhance(float(self.sharpness))
        print("image saved ", self.ui.scanpath.text() + "/" + pf)
        image.save(path + pf)

    @pyqtSlot()
    def leditcolor(self):
        self.ui.scanpath.setStyleSheet("background-color:rgb(255, 255, 255)")
        self.ui.filename.setStyleSheet("background-color:rgb(255, 255, 255)")

    def startScanJob(self):

        # print("Path: ",self.scanpath.text())
        # print("Mode: ",mode)
        # print("Resolution: ", self.resolutions.currentText())
        # print("File: ", self.filename.text())

        if len(self.ui.scanpath.text()) == 0:
            msg = QMessageBox()
            msg.setText("Please enter file path!")
            msg.exec()
            self.ui.scanpath.setStyleSheet(
                "background-color:rgb(255, 170, 127)")
            return

        if len(self.ui.filename.text()) == 0:
            msg = QMessageBox()
            msg.setText("Please enter file name prefix!")
            msg.exec()
            self.ui.filename.setStyleSheet(
                "background-color:rgb(255, 170, 127)")
            return

        if not self.scanStatus:
            self.setScanButton("starting")
            self.startThread(self.scannerCheck, self.setScannerStatus,
                             self.scannerCheckThreadEnd)
            self.scanStatus = True
            self.ui.scanpath.setEnabled(False)
            self.ui.filename.setEnabled(False)
        else:
            self.scanStatus = False
            self.setScanButton("stopped")
            self.ui.scanpath.setEnabled(True)
            self.ui.filename.setEnabled(True)
            self.ui.filename.clear()

            if self.ocr and len(self.ocrFiles) > 0:
                self.ui.btnOcr.setEnabled(True)
                self.tempocr = tempfile.NamedTemporaryFile(delete=False)
                for f in self.ocrFiles:
                    self.tempocr.write(str(f + "\n").encode())
                self.tempocr.close()

    def setScanButton(self, status):

        if status == "starting":
            self.btnStyle = self.ui.btnStartscan.styleSheet()

            self.ui.btnStartscan.setStyleSheet("background-color: yellow")
            self.ui.btnStartscan.setText("Starting...")

        if status == "running":
            self.ui.btnStartscan.setStyleSheet("background-color: red")
            self.ui.btnStartscan.setText("Stop")
            self.statusBar().showMessage("Scan job is running..")

        if status == "stopped":
            self.ui.btnStartscan.setText("Sart Scan")
            self.ui.btnStartscan.setStyleSheet(self.btnStyle)

    def configureWindow(self):

        if self.dev is not None:
            self.configWin.ui.scanButton.setEnabled(True)
            self.configWin.ui.scanButton.setText("Start Scan")
        else:
            self.configWin.ui.scanButton.setEnabled(False)
            self.configWin.ui.scanButton.setText("Sart Scan Service first")

        self.configWin.show()

    def ocr_startProcess(self):
        self.progressDlg = QProgressDialog(self)
        self.progressDlg.setWindowTitle("OCR Process")
        self.progressDlg.setLabelText("OCR Process in Progress ...")
        self.progressDlg.setAutoClose(False)
        self.progressDlg.setAutoReset(False)
        self.progressDlg.setModal(True)
        self.startThread(self.ocr_process, None, self.ocr_stopped)

    def ocr_process(self):

        if len(self.ocrFiles) > 0:

            val = 0
            ### add one more for pdf create process
            max = len(self.ocrFiles) + 1
            self.progressDlg.setRange(0, max)

            for f in self.ocrFiles:
                val += 1

                self.progressDlg.setValue(val)

                #TODO: if is checked
                ocrt.deskew(f)
                #TODO: if is checked
                #NOTE: this is crop and resize in one step
                #      size and dpi are predifined to A4 300
                print(self.cropSize)
                if self.cropSize['width'] > 1:
                    ocrt.crop_resize(f, self.cropSize["left"],
                                     self.cropSize["top"],
                                     self.cropSize["width"],
                                     self.cropSize["height"])
                #TODO: if is checked
                ocrt.check_orientation(f)

            print(self.tempocr.name)
            ## works in python 3.9+
            #pdfname = self.ocrFiles[0].removesuffix("_1.png")
            pdfname, suff = self.ocrFiles[0].rsplit("_1.png")
            print(pdfname)
            ### this runs in its own process
            self.progressDlg.setLabelText("OCR Process finishing ...")
            ocrt.create_pdf(self.tempocr.name, pdfname)
            ####
            ## Workaround to get a correct finished process
            ## while pytesseract uses subprocces which can not be handled in this thread
            ####
            while not os.path.isfile(pdfname + ".pdf"):
                time.sleep(3)
            self.progressDlg.setValue(val + 1)
            os.unlink(self.tempocr.name)
            self.ocrFiles.clear()
        else:
            return

    def ocr_stopped(self):
        print("OCR finished")
        self.progressDlg.close()

    def configScan(self):
        self.dev.resolution = int(self.ui.resolutions.currentText())
        self.dev.mode = self.checkScanMode()
        self.dev.start()
        im = self.dev.snap()
        pix = ImageQt.ImageQt(im.convert('RGBA'))
        #self.configWin.im = im
        #self.configWin.ui.view.setPixmap(self.configWin.pixmap.fromImage(pix))
        self.configWin.pixmapItem.setPixmap(QPixmap.fromImage(pix))
        self.configWin.ui.view.fitInView(self.configWin.pixmapItem,
                                         Qt.KeepAspectRatio)
        self.configWin.pixmapItem.grabMouse()
        self.configWin.setBufferImage()
        self.configWin.enhanceImage()
        #im = None

    @pyqtSlot()
    def saveConfig(self):
        self.brightness = self.configWin.ui.brigthnessLcd.value()
        self.contrast = self.configWin.ui.contrastLcd.value()
        self.color = self.configWin.ui.colorLcd.value()
        self.sharpness = self.configWin.ui.sharpnessLcd.value()
        self.crop = self.configWin.ui.checkCrop.isChecked()

        self.settings.setValue('brightness', self.brightness)
        self.settings.setValue('contrast', self.contrast)
        self.settings.setValue('color', self.color)
        self.settings.setValue('sharpness', self.sharpness)
        self.settings.setValue('ocr', self.ocr)
        self.settings.setValue('crop', self.crop)
        self.settings.setValue('cropSize', self.cropSize)
        self.settings.sync()
        self.configWin.close()

    @pyqtSlot(int)
    def ocrConfig(self, state):
        if state == Qt.Checked:
            self.ocr = True
            self.configWin.ui.OCR_Box.setEnabled(True)
        else:
            self.ocr = False
            self.configWin.ui.OCR_Box.setEnabled(False)

    def closeEvent(self, e):
        if self.tempocr is not None:
            if os.path.exists(self.tempocr.name):
                os.unlink(self.tempocr.name)
        if self.configWin.isVisible():
            self.configWin.close()

        e.accept()
Пример #9
0
class DuplicateImageFinderRuntime(QThread):
    dupes_found_event = pyqtSignal(int, list)
    scan_status_event = pyqtSignal(str, int, int, int, int, int, int)
    scan_finish_event = pyqtSignal()

    def __init__(self, files_to_scan, hash_size, h_dist_max, algorithm):
        super().__init__()
        self.files_to_scan = files_to_scan
        self.scan_size = len(files_to_scan)
        self.hash_size = hash_size
        self.h_dist_max = h_dist_max
        self.algorithm = algorithm
        self.stop = False
        self.status_counter = random.randint(5, 15)
        self.thread_pool = QThreadPool()
        self.connection, self.cursor = self._setup_database()
        self.cohort_counter = 0
        self.file_counter = 0

    def stop_scan(self):
        self.stop = True

    def run(self):
        self._start_duplicate_search2()

    def _process_file(self, hash_data):
        self.status_counter -= 1
        self.file_counter += 1

        cohort = None
        self.cursor.execute(
            '''SELECT file_name, cohort_id from file_details f 
                                WHERE hamming_dist(f.hash_code, ?) <= ?''', (
                hash_data.image_hash,
                self.h_dist_max,
            ))
        row = self.cursor.fetchone()
        if row is not None:
            found_file = row[0]
            cohort_id = row[1]
            if cohort_id is None:
                cohort = self.cohort_counter
                self.cohort_counter += 1
                # Update existing file
                self.cursor.execute(
                    '''UPDATE file_details SET cohort_id=? WHERE file_name=?''',
                    (
                        cohort,
                        found_file,
                    ))
            else:
                cohort = cohort_id

        # Insert new file
        self.cursor.execute(
            '''INSERT into file_details VALUES (?, ?, ?)''',
            (hash_data.file_name, hash_data.image_hash, cohort))

        # Raise an event if required
        if cohort is not None:
            self.cursor.execute(
                '''SELECT file_name from file_details WHERE 
                                                    cohort_id = ?''',
                (cohort, ))
            files = []
            for row in self.cursor:
                files.append(row[0])
            self.dupes_found_event.emit(cohort, files)

        if self.status_counter == 0:
            self.status_counter = random.randint(5, 15)
            self.scan_status_event.emit(hash_data.file_name, self.file_counter,
                                        self.scan_size,
                                        self.thread_pool.activeThreadCount(),
                                        self.thread_pool.maxThreadCount(), 0,
                                        0)

        if self.stop:
            self._close_database()
            self.scan_finish_event.emit()
            return

    def _start_duplicate_search2(self):
        while len(self.files_to_scan) > 0:
            if self.stop:
                self._close_database()
                self.scan_finish_event.emit()
                return

            file = self.files_to_scan.pop()
            worker = HashWorker(file, self.hash_size, self.algorithm)
            worker.signals.result.connect(self._process_file)
            worker.setAutoDelete(True)
            # Execute
            self.thread_pool.start(worker)

        self.thread_pool.waitForDone()
        self.scan_status_event.emit("", self.file_counter, self.scan_size,
                                    self.thread_pool.activeThreadCount(),
                                    self.thread_pool.maxThreadCount(), 0, 0)
        self.scan_finish_event.emit()

    def _setup_database(self):
        connection = sqlite3.connect(':memory:')
        cursor = connection.cursor()
        connection.create_function("hamming_dist", 2, self._hamming_distance)
        connection.row_factory = sqlite3.Row
        sqlite3.enable_callback_tracebacks(True)

        # Create table
        cursor.execute('''CREATE TABLE IF NOT EXISTS file_details (
                file_name text, 
                hash_code text, 
                cohort_id integer)''')
        cursor.execute(
            '''CREATE INDEX IF NOT EXISTS idx_hash on file_details(hash_code)'''
        )
        return connection, cursor

    def _close_database(self):
        self.cursor.close()
        self.connection.close()

    @staticmethod
    def _hamming_distance(s1, s2):
        """Return the Hamming distance between equal-length sequences"""
        if len(s1) != len(s2):
            raise ValueError("Undefined for sequences of unequal length")
        return sum(el1 != el2 for el1, el2 in zip(s1, s2))

    @staticmethod
    def _calculate_hash(file, hash_size):
        image = Image.open(file)
        return imagehash.average_hash(image, hash_size=hash_size)

    @staticmethod
    def _calculate_hash2(file, hash_size):
        image = Image.open(file)
        return HashedImage(file,
                           imagehash.average_hash(image, hash_size=hash_size))
Пример #10
0
class MainUI(MainWindow.Ui_MainWindow):
    def __init__(self, parent_window: QtWidgets.QMainWindow):
        self.parent_window = parent_window
        self.setupUi(self.parent_window)
        self.directoryListWidget = DirectoryListWidget()
        self.directoryListWidget.signals.dropped.connect(
            self.dropped_onto_list)
        self.startPushButton.clicked.connect(self.start)
        self.processing_thread_pool = QThreadPool()
        self.processing_thread_pool.setMaxThreadCount(1)
        self.setup_additional()
        self.stream = Stream()
        self.stream.newText.connect(self.add_line_to_stdout)
        sys.stdout = self.stream

    @property
    def reference_ending(self):
        return self.referenceEndingLineEdit.text(
        ) if self.referenceEndingLineEdit.text() != "" else None

    @property
    def filter(self):
        return self.filterCheckBox.checkState()

    @property
    def merge(self):
        return self.mergeCheckBox.checkState()

    @property
    def check(self):
        return self.checkCheckBox.checkState()

    @property
    def paths(self):
        paths = {}
        for i in range(self.directoryListWidget.count()):
            path = self.directoryListWidget.item(i).data(8)
            dir_name = os.path.dirname(path)
            try:
                paths[dir_name].append(path)
            except KeyError:
                paths[dir_name] = [path]
        return paths

    def __del__(self):
        try:
            sys.stdout = sys.__stdout__
        except AttributeError:
            pass

    def dropped_onto_list(self, paths):
        paths = self.get_paths(paths)
        for paths_list in paths:
            for path in paths_list:
                item = QtWidgets.QListWidgetItem(os.path.basename(path))
                item.setData(8, path)
                self.directoryListWidget.addItem(item)

    def get_paths(self, paths):
        path_list = [[]]
        for path in paths:
            if os.path.isdir(path):
                path_list.append(self.get_paths_from_directory(path))
            else:
                path_list[0].append(path)
        return path_list

    @staticmethod
    def get_paths_from_directory(directory):
        return [
            os.path.join(directory, f) for f in os.listdir(directory)
            if os.path.isfile(os.path.join(directory, f))
        ]

    def setup_additional(self):
        self.parent_window.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
        self.centralwidget.layout().addWidget(self.directoryListWidget, 1, 0)
        self.directoryListWidget.setAcceptDrops(True)

    def add_line_to_stdout(self, string):
        string = string.replace("\n", '')
        self.stdoutTextBrowser.append(string)

    def processing_finished(self):
        if self.processing_thread_pool.activeThreadCount() <= 0:
            self.startPushButton.setEnabled(True)

    def start(self):
        self.startPushButton.setEnabled(False)
        for path_dir, paths in self.paths.items():
            worker = Worker(self.start_processing_dir, path_dir, paths)
            worker.signals.finished.connect(self.processing_finished)
            self.processing_thread_pool.start(worker)

    def start_processing_dir(self, path_dir, paths):
        string_path_dir = path_dir.replace('\\\\', '/').replace('\\', '/')
        print(f"Started processing sounds from {string_path_dir}")
        process_sounds(paths, self.reference_ending, self.filter, self.check,
                       self.merge)
Пример #11
0
class MainWindow(QMainWindow):
    """
    You can use @pyqtSlot(int) syntax (with parameters), or you can pass this,
    but it make code more readable.
    Вы можете использовать синтаксис объявления слотов @pyqtSlot(int)
    с указанием типа передаваемых значений, или опустить его вовсе,
    однако это делает код нагляднее
    и позволяет быстро понять, что слот, а что - функция.
    """

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self._counter = 0
        self.init_ui()

        self._threadpool = QThreadPool()
        #self._threadpool = QtCore.QThreadPool.globalInstance()
        #self._threadpool.setMaxThreadCount(2)
        print("Multithreading with maximum {} threads" .format(self._threadpool.maxThreadCount()))

        self._timer = QTimer()
        self._timer.setInterval(1000)
        self._timer.timeout.connect(self.recurring_timer)
        self._timer.start()

    def init_ui(self):
        layout = QVBoxLayout()

        self._label = QLabel("Start")
        b = QPushButton("Start QRunnable")
        b.pressed.connect(self.start_new_runnable)

        layout.addWidget(self._label)
        layout.addWidget(b)

        w = QWidget()
        w.setLayout(layout)

        self.setCentralWidget(w)

    @pyqtSlot(int)
    def thread_progress_fn(self, n):
        print("{}% done".format(n))

    @pyqtSlot(object)
    def thread_print_output(self, s):
        print('Result: {}'.format(s))

    @pyqtSlot()
    def thread_complete(self):
        print("QRunnable worker COMPLETE!")

    @pyqtSlot(tuple)
    def thread_error(self, err):
        QMessageBox.warning(self, "Warning!", err[1], QMessageBox.Ok)
        print('Error {}\n{}'.format(err[1], err[2]))

    @pyqtSlot()
    def start_new_runnable(self):
        # Pass the function to execute
        worker = Worker(1, debug=True) # Any other args, kwargs are passed to the run function
        worker.signals.result.connect(self.thread_print_output)
        worker.signals.finished.connect(self.thread_complete)
        worker.signals.progress.connect(self.thread_progress_fn)
        worker.signals.error.connect(self.thread_error)
        worker.setAutoDelete(True)
        # Execute (tryStart() better than start() )
        if self._threadpool.tryStart(worker) is False:
            print("Can't create worker!")
            QMessageBox.warning(self, "Warning!", "Can't create worker!", QMessageBox.Ok)

    @pyqtSlot()
    def recurring_timer(self):
        self._counter += 1
        self._label.setText("Counter: {}".format(self._counter))
        print('Active thread count: {}'.format(self._threadpool.activeThreadCount()))

    def closeEvent(self, event):
        """Main window closed, override PyQt5 widget function"""
        print('Try to exit, active thread count: {}'.format(self._threadpool.activeThreadCount()))
        reply = QMessageBox.question(self, 'Message',
                                     "Are you sure to quit?", QMessageBox.Yes |
                                     QMessageBox.No, QMessageBox.No)
        if reply == QMessageBox.Yes:
            self._threadpool.waitForDone()
            self._timer.stop()
            event.accept()
        else:
            event.ignore()
Пример #12
0
class Main_Window_class(QDialog):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        ### Hyperparameters ###
        self.nlabels = 6

        self.checkboxes_lables = ['Клиппинг', 'Энвелоп']
        self.btns_lables = ['Воспроизвести', 'Пауза', 'Остановить']
        self.app_name = 'Эквалайзер'

        self.sld_min = -50
        self.sld_max = 50
        self.sld_def = 0
        self.sld_interval = 10
        self.sld_step = 1
        #######################

        ### Global variables ###
        self.path_to_pull = None

        self.nchannels = None  # number of channels
        self.sampwidth = None  # number of bytes per sample
        self.framerate = None  # number of frames per second
        self.nframes = None  # total number of frames
        self.comptype = None  # compression type
        self.compname = None  # compression type name
        self.elem_per_herz = None
        self.koeff = 1000  # коэффициент прореживания
        self.types = {}
        self.buffer_size = None
        self.buffer_cnt = 0

        self.music_is_playing = False
        self.threadpool = QThreadPool()
        print(self.threadpool.maxThreadCount())

        self.music_worker = None
        self.sld1_worker = None
        self.sld2_worker = None
        self.sld3_worker = None
        self.sld4_worker = None
        self.sld5_worker = None
        self.sld6_worker = None
        self.checkbox1_worker = None
        self.checkbox2_worker = None

        self.min_freq = 0
        self.max_freq = None

        self.channels = []
        self.spectrum = None
        self.spectrum_original = None
        self.spectrum_kliping = None
        self.spectrum_envelop = None
        self.channels_original = []
        self.channels_kliping = []
        self.channels_envelop = []

        self.bands = [[], []]
        self.labels = []
        ########################

        ### Links ###
        #         https://habrahabr.ru/post/113239/
        #         http://old.pynsk.ru/posts/2015/Nov/09/matematika-v-python-preobrazovanie-fure/
        #         http://www.7not.ru/articles/klip_cool.phtml
        #         https://martinfitzpatrick.name/article/multithreading-pyqt-applications-with-qthreadpool/
        #         https://www.tutorialspoint.com/pyqt/pyqt_qlineedit_widget.htm
        #         https://stackoverflow.com/questions/21887862/python-chorus-effect-and-meaning-of-audio-data
        #         http://websound.ru/articles/sound-processing/effects.htm
        #         http://www.auditionrich.com/lessons/kak-v-adobe-audition-ispolzovat-effekt-envelope-follower.html
        #         https://works.doklad.ru/view/M_cHUqES_HE/2.html
        #############

        self.path_to_pull = QFileDialog.getOpenFileName(
            self, 'Выберите .wav файл')[0]

        self.pull_music()
        self.create_bands()
        self.create_lables()
        self.create_LCD_numbers()
        self.create_sliders()
        self.create_checkboxes()
        self.create_buttons()
        self.create_graphics()
        self.create_interface()

    def pull_music(self):
        wav = wave.open(self.path_to_pull, mode='r')
        self.types = {1: np.int8, 2: np.int16, 4: np.int32}

        (self.nchannels, self.sampwidth, self.framerate, self.nframes,
         self.comptype, self.compname) = wav.getparams()

        self.max_freq = self.framerate // 2
        self.buffer_size = self.framerate

        content = wav.readframes(self.nframes)
        samples = np.fromstring(content, dtype=self.types[self.sampwidth])

        for i in range(self.nchannels):
            self.channels.append(samples[i::self.nchannels])
        self.channels = np.array(self.channels)

        self.channels_original = self.channels.copy()

        self.checkbox1_worker = Worker(self.doing_kliping, self.channels)
        self.threadpool.start(self.checkbox1_worker)

        self.checkbox2_worker = Worker(self.doing_envelop, self.channels)
        self.threadpool.start(self.checkbox2_worker)

        self.spectrum = np.fft.rfft(self.channels_original)
        self.spectrum_original = self.spectrum.copy()

        pygame.mixer.pre_init(frequency=self.framerate,
                              size=-self.sampwidth * 8,
                              channels=self.nchannels)
        pygame.init()

    def create_bands(self):
        step = (self.max_freq - self.min_freq) // 2**self.nlabels

        self.bands[0].append(self.min_freq)
        self.bands[1].append(self.min_freq + step)

        for i in range(1, self.nlabels - 1):
            self.bands[0].append(self.bands[1][i - 1])
            self.bands[1].append(self.bands[0][i] + 2**i * step)

        self.bands[0].append(self.bands[1][self.nlabels - 2])
        self.bands[1].append(self.max_freq)

        for i in range(self.nlabels):
            self.labels.append(
                str(self.bands[0][i]) + ' - ' + str(self.bands[1][i]))

    def create_lables(self):
        self.label_1 = QLabel(self.labels[0], self)
        self.label_2 = QLabel(self.labels[1], self)
        self.label_3 = QLabel(self.labels[2], self)
        self.label_4 = QLabel(self.labels[3], self)
        self.label_5 = QLabel(self.labels[4], self)
        self.label_6 = QLabel(self.labels[5], self)

    def create_LCD_numbers(self):
        self.num_1 = QLCDNumber(self)
        self.num_2 = QLCDNumber(self)
        self.num_3 = QLCDNumber(self)
        self.num_4 = QLCDNumber(self)
        self.num_5 = QLCDNumber(self)
        self.num_6 = QLCDNumber(self)

    def create_sliders(self):
        self.sld_1 = QSlider(Qt.Vertical, self)
        self.sld_2 = QSlider(Qt.Vertical, self)
        self.sld_3 = QSlider(Qt.Vertical, self)
        self.sld_4 = QSlider(Qt.Vertical, self)
        self.sld_5 = QSlider(Qt.Vertical, self)
        self.sld_6 = QSlider(Qt.Vertical, self)

        self.sld_1.setMinimum(self.sld_min)
        self.sld_2.setMinimum(self.sld_min)
        self.sld_3.setMinimum(self.sld_min)
        self.sld_4.setMinimum(self.sld_min)
        self.sld_5.setMinimum(self.sld_min)
        self.sld_6.setMinimum(self.sld_min)

        self.sld_1.setMaximum(self.sld_max)
        self.sld_2.setMaximum(self.sld_max)
        self.sld_3.setMaximum(self.sld_max)
        self.sld_4.setMaximum(self.sld_max)
        self.sld_5.setMaximum(self.sld_max)
        self.sld_6.setMaximum(self.sld_max)

        self.sld_1.setValue(self.sld_def)
        self.sld_2.setValue(self.sld_def)
        self.sld_3.setValue(self.sld_def)
        self.sld_4.setValue(self.sld_def)
        self.sld_5.setValue(self.sld_def)
        self.sld_6.setValue(self.sld_def)

        self.sld_1.setFocusPolicy(Qt.StrongFocus)
        self.sld_2.setFocusPolicy(Qt.StrongFocus)
        self.sld_3.setFocusPolicy(Qt.StrongFocus)
        self.sld_4.setFocusPolicy(Qt.StrongFocus)
        self.sld_5.setFocusPolicy(Qt.StrongFocus)
        self.sld_6.setFocusPolicy(Qt.StrongFocus)

        self.sld_1.setTickPosition(QSlider.TicksBothSides)
        self.sld_2.setTickPosition(QSlider.TicksBothSides)
        self.sld_3.setTickPosition(QSlider.TicksBothSides)
        self.sld_4.setTickPosition(QSlider.TicksBothSides)
        self.sld_5.setTickPosition(QSlider.TicksBothSides)
        self.sld_6.setTickPosition(QSlider.TicksBothSides)

        self.sld_1.setTickInterval(self.sld_interval)
        self.sld_2.setTickInterval(self.sld_interval)
        self.sld_3.setTickInterval(self.sld_interval)
        self.sld_4.setTickInterval(self.sld_interval)
        self.sld_5.setTickInterval(self.sld_interval)
        self.sld_6.setTickInterval(self.sld_interval)

        self.sld_1.setSingleStep(self.sld_step)
        self.sld_2.setSingleStep(self.sld_step)
        self.sld_3.setSingleStep(self.sld_step)
        self.sld_4.setSingleStep(self.sld_step)
        self.sld_5.setSingleStep(self.sld_step)
        self.sld_6.setSingleStep(self.sld_step)

        self.sld_1.valueChanged[int].connect(self.sliderChangeValue)
        self.sld_2.valueChanged[int].connect(self.sliderChangeValue)
        self.sld_3.valueChanged[int].connect(self.sliderChangeValue)
        self.sld_4.valueChanged[int].connect(self.sliderChangeValue)
        self.sld_5.valueChanged[int].connect(self.sliderChangeValue)
        self.sld_6.valueChanged[int].connect(self.sliderChangeValue)

        self.sld_1.valueChanged[int].connect(self.num_1.display)
        self.sld_2.valueChanged[int].connect(self.num_2.display)
        self.sld_3.valueChanged[int].connect(self.num_3.display)
        self.sld_4.valueChanged[int].connect(self.num_4.display)
        self.sld_5.valueChanged[int].connect(self.num_5.display)
        self.sld_6.valueChanged[int].connect(self.num_6.display)

        self.old_value_sld1 = self.sld_def
        self.old_value_sld2 = self.sld_def
        self.old_value_sld3 = self.sld_def
        self.old_value_sld4 = self.sld_def
        self.old_value_sld5 = self.sld_def
        self.old_value_sld6 = self.sld_def

    def create_checkboxes(self):
        self.checkbox_1 = QCheckBox(self.checkboxes_lables[0], self)
        self.checkbox_2 = QCheckBox(self.checkboxes_lables[1], self)

        self.checkbox_1.setChecked(False)
        self.checkbox_2.setChecked(False)

        self.checkbox_1.stateChanged.connect(self.checkboxClicked)
        self.checkbox_2.stateChanged.connect(self.checkboxClicked)

    def create_buttons(self):
        self.btn_1 = QPushButton(self.btns_lables[0], self)
        self.btn_2 = QPushButton(self.btns_lables[1], self)
        self.btn_3 = QPushButton(self.btns_lables[2], self)

        self.btn_1.clicked.connect(self.buttonClicked)
        self.btn_2.clicked.connect(self.buttonClicked)
        self.btn_3.clicked.connect(self.buttonClicked)

    def create_graphics(self):
        figure_1 = plt.figure()
        self.figure_2 = plt.figure()
        self.figure_4 = plt.figure()

        self.canvas_1 = FigureCanvas(figure_1)
        self.canvas_2 = FigureCanvas(self.figure_2)
        self.canvas_4 = FigureCanvas(self.figure_4)

        self.toolbar_1 = NavigationToolbar(self.canvas_1, self)
        self.toolbar_2 = NavigationToolbar(self.canvas_2, self)
        self.toolbar_4 = NavigationToolbar(self.canvas_4, self)

        figure_1.clear()
        self.figure_2.clear()
        self.figure_4.clear()

        ax_1 = figure_1.add_subplot(1, 1, 1)
        self.ax_2 = self.figure_2.add_subplot(1, 1, 1)
        self.ax_4 = self.figure_4.add_subplot(1, 1, 1)

        ax_1.set_xlabel('Частота, Гц')
        self.ax_2.set_xlabel('Частота, Гц')
        self.ax_4.set_xlabel('Время, с')

        figure_1.align_xlabels()
        self.figure_2.align_xlabels()
        self.figure_4.align_xlabels()

        ax_1.set_ylabel('Амплитуда')
        self.ax_2.set_ylabel('Амплитуда')
        self.ax_4.set_ylabel('Амплитуда')

        figure_1.align_ylabels()
        self.figure_2.align_ylabels()
        self.figure_4.align_ylabels()

        self.elem_per_herz = self.spectrum.shape[1] // (self.max_freq -
                                                        self.min_freq)

        ax_1.plot(
            np.fft.rfftfreq(self.nframes, 1. / self.framerate)[::self.koeff],
            np.abs(self.spectrum[0][::self.koeff]) / self.nframes)

        self.ax_2.plot(
            np.fft.rfftfreq(self.nframes, 1. / self.framerate)[::self.koeff],
            np.abs(self.spectrum[0][::self.koeff]) / self.nframes)
        self.ax_4.plot(self.channels[0][::self.koeff])

        self.canvas_1.draw()
        self.canvas_2.draw()
        self.canvas_4.draw()

    def create_interface(self):
        self.labels_box = QHBoxLayout()
        self.labels_box.addWidget(self.label_1)
        self.labels_box.addWidget(self.label_2)
        self.labels_box.addWidget(self.label_3)
        self.labels_box.addWidget(self.label_4)
        self.labels_box.addWidget(self.label_5)
        self.labels_box.addWidget(self.label_6)

        self.nums_box = QHBoxLayout()
        self.nums_box.addWidget(self.num_1)
        self.nums_box.addWidget(self.num_2)
        self.nums_box.addWidget(self.num_3)
        self.nums_box.addWidget(self.num_4)
        self.nums_box.addWidget(self.num_5)
        self.nums_box.addWidget(self.num_6)

        self.slds_box = QHBoxLayout()
        self.slds_box.addWidget(self.sld_1)
        self.slds_box.addWidget(self.sld_2)
        self.slds_box.addWidget(self.sld_3)
        self.slds_box.addWidget(self.sld_4)
        self.slds_box.addWidget(self.sld_5)
        self.slds_box.addWidget(self.sld_6)

        self.graphs_box_1 = QVBoxLayout()
        self.graphs_box_1.addWidget(self.toolbar_4)
        self.graphs_box_1.addWidget(self.canvas_4)

        self.checks_and_btns_box = QHBoxLayout()
        self.checks_and_btns_box.addWidget(self.checkbox_1)
        self.checks_and_btns_box.addWidget(self.checkbox_2)
        self.checks_and_btns_box.addWidget(self.btn_1)
        self.checks_and_btns_box.addWidget(self.btn_2)
        self.checks_and_btns_box.addWidget(self.btn_3)

        self.graphs_box_2 = QVBoxLayout()
        self.graphs_box_2.addWidget(self.toolbar_1)
        self.graphs_box_2.addWidget(self.canvas_1)
        self.graphs_box_2.addWidget(self.toolbar_2)
        self.graphs_box_2.addWidget(self.canvas_2)

        self.left_box = QVBoxLayout()
        self.left_box.addLayout(self.labels_box)
        self.left_box.addLayout(self.slds_box)
        self.left_box.addLayout(self.nums_box)
        self.left_box.addLayout(self.graphs_box_1)

        self.right_box = QVBoxLayout()
        self.right_box.addLayout(self.checks_and_btns_box)
        self.right_box.addLayout(self.graphs_box_2)

        self.all_box = QHBoxLayout()
        self.all_box.addLayout(self.left_box)
        self.all_box.addLayout(self.right_box)

        self.setLayout(self.all_box)

        self.setWindowTitle(self.app_name)
        self.showMaximized()

    def sliderChangeValue(self, value):
        if (self.sender() == self.sld_1):
            self.sld1_worker = Worker(self.music_edit, 0, value)
            self.threadpool.start(self.sld1_worker)

        elif (self.sender() == self.sld_2):
            self.sld2_worker = Worker(self.music_edit, 1, value)
            self.threadpool.start(self.sld2_worker)

        elif (self.sender() == self.sld_3):
            self.sld3_worker = Worker(self.music_edit, 2, value)
            self.threadpool.start(self.sld3_worker)

        elif (self.sender() == self.sld_4):
            self.sld4_worker = Worker(self.music_edit, 3, value)
            self.threadpool.start(self.sld4_worker)

        elif (self.sender() == self.sld_5):
            self.sld5_worker = Worker(self.music_edit, 4, value)
            self.threadpool.start(self.sld5_worker)

        else:
            self.sld6_worker = Worker(self.music_edit, 5, value)
            self.threadpool.start(self.sld6_worker)

    def checkboxClicked(self, state):
        if (self.sender() == self.checkbox_1):
            if (state == Qt.Checked):
                self.checkbox_2.setChecked(False)
                self.channels = self.channels_kliping.copy()
                self.spectrum = self.spectrum_kliping.copy()
            else:
                self.channels = self.channels_original.copy()
                self.spectrum = self.spectrum_original.copy()

        else:
            if (state == Qt.Checked):
                self.checkbox_1.setChecked(False)
                self.channels = self.channels_envelop.copy()
                self.spectrum = self.spectrum_envelop.copy()
            else:
                self.channels = self.channels_original.copy()
                self.spectrum = self.spectrum_original.copy()

        self.sld_1.setValue(self.sld_def)
        self.sld_2.setValue(self.sld_def)
        self.sld_3.setValue(self.sld_def)
        self.sld_4.setValue(self.sld_def)
        self.sld_5.setValue(self.sld_def)
        self.sld_6.setValue(self.sld_def)

        draw_1 = Worker(self.draw_array, self.spectrum, 0)
        self.threadpool.start(draw_1)

        draw_2 = Worker(self.draw_array, self.channels, 1)
        self.threadpool.start(draw_2)

    def buttonClicked(self):
        if (self.sender() == self.btn_1):
            if (self.music_is_playing == False):
                self.music_is_playing = True
                self.music_worker = Worker(self.start_music)
                self.threadpool.start(self.music_worker)

        elif (self.sender() == self.btn_2):
            if (self.music_is_playing == True):
                self.music_is_playing = False

        else:
            if (self.music_is_playing == True):
                self.music_is_playing = False
                self.threadpool.clear()

            sliders = [
                self.sld1_worker, self.sld2_worker, self.sld3_worker,
                self.sld4_worker, self.sld5_worker, self.sld6_worker
            ]
            for slider in sliders:
                self.sld_stop(slider)

            self.buffer_cnt = 0

            self.sld_1.setValue(self.sld_def)
            self.sld_2.setValue(self.sld_def)
            self.sld_3.setValue(self.sld_def)
            self.sld_4.setValue(self.sld_def)
            self.sld_5.setValue(self.sld_def)
            self.sld_6.setValue(self.sld_def)

            self.checkbox_1.setChecked(False)
            self.checkbox_2.setChecked(False)

            tmp_worker = Worker(self.tmp_func)
            self.threadpool.start(tmp_worker)

    def sld_stop(self, slider):
        ids = {
            self.sld1_worker: 0,
            self.sld2_worker: 1,
            self.sld3_worker: 2,
            self.sld4_worker: 3,
            self.sld5_worker: 4,
            self.sld6_worker: 5
        }

        slider = Worker(self.music_edit, ids[slider], self.sld_def)
        self.threadpool.start(slider)

    def tmp_func(self):
        while (self.threadpool.activeThreadCount() != 1):
            sleep(0.1)
        self.channels = self.channels_original.copy()
        self.spectrum = self.spectrum_original.copy()
        print('music stopped')

    def start_music(self):
        tmp_channels = []
        tmp_channels.append(
            self.channels[0][self.buffer_cnt *
                             self.buffer_size:(self.buffer_cnt + 1) *
                             self.buffer_size + 1:])
        tmp_channels.append(
            self.channels[1][self.buffer_cnt *
                             self.buffer_size:(self.buffer_cnt + 1) *
                             self.buffer_size + 1:])
        tmp_channels = np.array(tmp_channels)
        tmp_channels = np.ascontiguousarray(tmp_channels.T)
        tmp_sound = pygame.sndarray.make_sound(tmp_channels)

        sound = tmp_sound
        if (self.music_is_playing == False):
            return
        pygame.mixer.Sound.play(sound)

        start_pos = self.buffer_cnt
        for self.buffer_cnt in range(start_pos + 1,
                                     self.nframes // self.buffer_size):
            tmp_channels = []
            tmp_channels.append(
                self.channels[0][self.buffer_cnt *
                                 self.buffer_size:(self.buffer_cnt + 1) *
                                 self.buffer_size + 1:])
            tmp_channels.append(
                self.channels[1][self.buffer_cnt *
                                 self.buffer_size:(self.buffer_cnt + 1) *
                                 self.buffer_size + 1:])
            tmp_channels = np.array(tmp_channels)
            tmp_channels = np.ascontiguousarray(tmp_channels.T)
            tmp_sound = pygame.sndarray.make_sound(tmp_channels)

            while (pygame.mixer.get_busy()):
                sleep(0.01)

            sound = tmp_sound
            if (self.music_is_playing == False):
                return
            pygame.mixer.Sound.play(sound)

        tmp_channels = []
        tmp_channels.append(self.channels[0][self.buffer_cnt *
                                             self.buffer_size::])
        tmp_channels.append(self.channels[1][self.buffer_cnt *
                                             self.buffer_size::])
        tmp_channels = np.array(tmp_channels)
        tmp_channels = np.ascontiguousarray(tmp_channels.T)
        tmp_sound = pygame.sndarray.make_sound(tmp_channels)

        while (pygame.mixer.get_busy()):
            sleep(0.01)

        sound = tmp_sound
        if (self.music_is_playing == False):
            return
        pygame.mixer.Sound.play(sound)

        self.buffer_cnt = 0
        self.music_is_playing = False

    def music_edit(self, pos, value):
        old_values = {
            0: self.old_value_sld1,
            1: self.old_value_sld2,
            2: self.old_value_sld3,
            3: self.old_value_sld4,
            4: self.old_value_sld5,
            5: self.old_value_sld6
        }
        old_value = old_values[pos]

        if pos == 0:
            self.old_value_sld1 = value
        elif pos == 1:
            self.old_value_sld2 = value
        elif pos == 2:
            self.old_value_sld3 = value
        elif pos == 3:
            self.old_value_sld4 = value
        elif pos == 4:
            self.old_value_sld5 = value
        else:
            self.old_value_sld6 = value

        if (old_value == value):
            return

        if (pos == 0):
            for i in range(self.nchannels):
                self.spectrum[i][:self.elem_per_herz * self.bands[1][pos] +
                                 1] *= 10**((value - old_value) / 20)

        elif (pos == 5):
            for i in range(self.nchannels):
                self.spectrum[i][self.elem_per_herz *
                                 self.bands[0][pos]:] *= 10**(
                                     (value - old_value) / 20)

        else:
            for i in range(self.nchannels):
                self.spectrum[i][self.elem_per_herz *
                                 self.bands[0][pos]:self.elem_per_herz *
                                 self.bands[1][pos] +
                                 1] *= 10**((value - old_value) / 20)

        self.channels = (np.fft.irfft(self.spectrum)).astype(
            self.types[self.sampwidth])

        draw_1 = Worker(self.draw_array, self.spectrum, 0)
        self.threadpool.start(draw_1)

        draw_2 = Worker(self.draw_array, self.channels, 1)
        self.threadpool.start(draw_2)

    def draw_array(self, arr, spectrum_or_channel):
        if (spectrum_or_channel == 0):
            self.figure_2.clear()
            self.ax_2 = self.figure_2.add_subplot(1, 1, 1)
            self.ax_2.set_xlabel('Частота, Гц')
            self.figure_2.align_xlabels()
            self.ax_2.set_ylabel('Амплитуда')
            self.figure_2.align_ylabels()
            self.ax_2.plot(
                np.fft.rfftfreq(self.nframes,
                                1. / self.framerate)[::self.koeff],
                np.abs(arr[0][::self.koeff]) / self.nframes)
            self.canvas_2.draw()

        else:
            self.figure_4.clear()
            self.ax_4 = self.figure_4.add_subplot(1, 1, 1)
            self.ax_4.set_xlabel('Время, с')
            self.figure_4.align_xlabels()
            self.ax_4.set_ylabel('Амплитуда')
            self.figure_4.align_ylabels()
            self.ax_4.plot(arr[0][::self.koeff])
            self.canvas_4.draw()

    def doing_kliping(self, channels):
        print('kliping start')
        start_time = time()
        threshold_max = int(0.6 * np.max(channels[0]))
        threshold_min = int(0.6 * np.min(channels[0]))

        self.channels_kliping = np.maximum(np.minimum(channels, threshold_max),
                                           threshold_min).astype(
                                               self.types[self.sampwidth])
        self.spectrum_kliping = np.fft.rfft(self.channels_kliping)
        print('kliping end: ' + str(time() - start_time))

    def doing_envelop(self, channels):
        print('envelop start')
        start_time = time()
        frequency = 1 / 15
        envelope_sig = np.array([
            abs(sin(2 * pi * frequency * t / self.framerate))
            for t in range(self.nframes)
        ])
        tmp_channels = channels.copy()

        for i in range(self.nchannels):
            tmp_channels[i] = (tmp_channels[i] * envelope_sig).astype(
                self.types[self.sampwidth])

        self.channels_envelop = tmp_channels.copy()
        self.spectrum_envelop = np.fft.rfft(self.channels_envelop)
        print('envelop end: ' + str(time() - start_time))
Пример #13
0
class BackupManager(): #A hub to manage all Backups
    def __init__(self, dir):
        self.threadpool = QThreadPool()
        self.subthreadpool = QThreadPool()
        self.threads = 0
        self.BackupDirectory = dir
        self.BackupStorage = {}
        self.load_from_txt()
        self.load_prev_from_json()
        print("Backup Manager initiated: " + dir)
        self.print()
    def getAmountOfThreads(self):
        return self.threadpool.activeThreadCount()
    def close(self):
        try:
            self.save_prev_to_json()
            self.save_to_txt()
            self.cleanup()
        except: print("closing failed")
    def addBackup(self, b):
        assert isinstance(b, Backup), 'Not a Backup!'
        name = b.getName()
        if name not in self.BackupStorage:
            self.BackupStorage[name] = [b]
            print("New Backup Entry Created: " + name)
            return True
        else:
            temp = self.BackupStorage[name]
            for i in temp:
                if (b.getDirectory() == i.getDirectory()):
                    return False
            temp.append(b)
            self.BackupStorage[name] = temp
            print("Added Entry to existing Backup: " + name)
            return True
    def newBackup(self, name, dir, date = datetime.now(). strftime("%d_%m_%Y-%H_%M_%S")):
        try:
            b = Backup(name, dir, date)
        except(AssertionError):
            print("Backup initiation failed due to invalid inputs")
            return False
        self.addBackup(b)
        return True
    def moveBackupManager(self, newdir):
        tempbdir = self.BackupDirectory
        self.BackupDirectory = newdir
        self.threads += 1
        print(tempbdir)
        print(newdir)


    def backupALL(self):
        for b in self.BackupStorage.keys():
            self.back_up_threaded(b)
    def back_up_threaded(self, b):
        self.threads += 1
        worker = CopyWorker(self.back_up, b, self.BackupDirectory)
        worker.signals.finished.connect(self.thread_complete)
        self.threadpool.start(worker)
    def back_up(self, b, bdir):
        self.link_Backup(b, datetime.now(). strftime("%d_%m_%Y-%H_%M_%S"))
        self.save_Backup(b, bdir)
    def link_Backup(self, key, date, mode=0):
        dir = key + r'/'
        if (self.BackupStorage[key].__len__() == 1 or mode==1):
            for b in self.BackupStorage[key]:
                b.setDate(date)
                folder = os.path.basename(b.getDirectory())
                name = folder + "_" + date
                b.setBackupLocation(dir+name)
        else:
            i = 0
            for b in self.BackupStorage[key]:
                b.setDate(date)
                folder = os.path.basename(b.getDirectory())
                i+=1
                name = folder + "_" + date
                b.setBackupLocation(dir+ str(i) + "_" +name)
    def save_Backup(self, key, bdir):
        for b in self.BackupStorage[key]:
            b.savetoBackupLocation (bdir)
    def getAll(self):
        return self.BackupStorage.keys()
    def getinfo(self, key):
        l = []
        for i in self.BackupStorage[key]:
            for p in i.returnData():
                l.append(p)
        return l
    def thread_complete(self):
        self.threads -=1
        print(self.threads)
        if self.threads == 0:
            print("All Done")
    def print(self):
        for b in self.BackupStorage.keys():
            print("-----" + b + "-----")
            for i in self.BackupStorage[b]:
                i.printData()
    def save_prev_to_json(self):
        for b in self.BackupStorage.keys():
            c = 0
            for i in self.BackupStorage[b]:
                c+=1
                try:
                    f = open(self.BackupDirectory + "//" + b +"_"+  str(c) + "_prev.json", 'w')
                    f.write(json.dumps(i.getPrevious()))
                    f.close()
                except: print("couldn't save previous for: " + b+ "_" + str(i))
    def load_prev_from_json(self):
        for b in self.BackupStorage.keys():
            c = 0
            for i in self.BackupStorage[b]:
                c += 1
                try:
                    with open(self.BackupDirectory + "\\" + b +"_"+ str(c) + "_prev.json", 'r') as json_file:
                        data = json.load(json_file)
                        i.setPrevious(data)
                except: print("couldn't load json file: " + self.BackupDirectory + "\\" + b +"_"+  str(c) + "_prev.json")
    def save_to_txt(self, dir = ""):
        f = open(self.BackupDirectory + r"/backup.txt", 'w')
        for b in self.BackupStorage.keys():
            f.write("Name: " + b )
            for i in self.BackupStorage[b]:
                f.write("Date: " + i.getDate())
                f.write("Directory: " + i.getDirectory())
                f.write("Backupdirectory: " + i.getBackupLocation())
            f.write("\n")
        f.close()
    def load_from_txt(self):
        try:
            f = open(self.BackupDirectory + "\\backup.txt", 'r')
            for l in f.readlines():
                temp = re.split('Name: |Date: |Directory: |Backupdirectory: ', l.strip("\n"))
                temp.pop(0)
                self.load_entry(temp)
            f.close()
            print("Successfully loaded backup.txt")
        except: print("Couldn't load backup.txt")
    def load_entry(self, l):
        name = l.pop(0)
        while(l!=[]):
            date = l.pop(0)
            dir = l.pop(0)
            bdir = l.pop(0)
            b = Backup(name, dir, date = date)
            b.setBackupLocation(bdir)
            self.addBackup(b)
    def clear_all(self):
        self.BackupStorage = {}
    def cleanup(self): #deletes empty directories in Backup Folder
        print("-Cleanup-")
        count = 0
        for i in os.listdir(self.BackupDirectory):
            try:
                os.rmdir(os.path.join(self.BackupDirectory, i))
                count+=1
            except: print("Didn't delete: " + i)
        print("Deleted " + str(count) + " folders")
    def deletePrevious(self):
        for b in self.BackupStorage.keys():
            for i in self.BackupStorage[b]:
                self.threads +=1
                worker = CopyWorker(i.deletePrevious, self.BackupDirectory)
                worker.signals.finished.connect(self.thread_complete)
                self.threadpool.start(worker)
    def deleteCurrent(self):
        for b in self.BackupStorage.keys():
            for i in self.BackupStorage[b]:
                i.deleteCurrent(self.BackupDirectory)
    def open_in_explorer(self, key):
        for b in self.BackupStorage[key]:
            b.open_in_explorer()
    def open_Backup_in_explorer(self, key):
        for b in self.BackupStorage[key]:
            try: b.open_Backup_in_explorer(self.BackupDirectory)
            except(AssertionError): print("Directory not valid")
    def deleteSpecific(self, b, str):
        print(self.BackupStorage[b])
        for i in self.BackupStorage[b]:
            if i.deleteFromString(str, self.BackupDirectory):
                self.BackupStorage[b].remove(i)
        if self.BackupStorage[b]== []:
            del self.BackupStorage[b]
    def setEF(self, key, eFlag, str = ""):
        if str=="":
            for i in self.BackupStorage[key]:
                i.setEnabledFlag(eFlag)
        else:
            for i in self.BackupStorage[key]:
                if i.checkifstringiscurrent(str):
                    i.setEnabledFlag(eFlag)
Пример #14
0
class ProgressWindow(QMainWindow, Ui_ProgressWindow):
    """Window that displays a list of jobs that are being performed.
        """
    def __init__(self, main_window: 'MainWindow', *args, **kwargs):
        """Constructor for ProgressWindow.

            Parameter
            ---------
            main_window : MainWindow -
                Send in the main window, so it can be hidden and shown.
            """
        super().__init__(*args, **kwargs)
        self.setupUi(self)
        self.main_window = main_window
        self.job_index = 0

        self.jobs_threadpool = QThreadPool()

        self.actionShow_Main_Window.toggled.connect(self.toggle_main_window)
        self.original_close_event = self.closeEvent  # type: ignore
        self.closeEvent = self._window_closed  # pylint: disable=invalid-name

    def toggle_main_window(self, toggled: bool):
        """Either hides or shows the main window.

            Parameters
            ----------
            toggled : bool -
                Whether the window should be shown.
            """
        if self.main_window is None:
            return
        self.main_window.setVisible(toggled)

    def _window_closed(self, event: QCloseEvent):
        """Reimplement the closeEvent method of this window.
            Toggle the action linked to this window in the
            main window to off.

            Parameters
            ----------
            event : QCloseEvent -
                The event that is sent when the window is closed.
            """
        self.main_window.actionCurrent_Jobs.setChecked(False)
        self.original_close_event(event)

    def create_new_job(self, created_actions: List[ActionToCreate]):
        """Creates a job that will be performed on the songs
            """
        created_job: List[Action] = []
        for index, created_action in enumerate(created_actions):
            action = Action(created_action, self.job_index, index)
            action.signals.action_started.connect(self.set_action_length)
            action.signals.action_progress\
                .connect(self.update_action_progress)
            action.signals.action_finished\
                .connect(self.update_action_complete)
            if action.subaction_signals is not None:
                action.subaction_signals.subaction_started\
                    .connect(self.set_subaction_length)
                action.subaction_signals.subaction_progress\
                    .connect(self.update_subaction_progress)
                action.subaction_signals.subaction_finished\
                    .connect(self.update_subaction_complete)
            created_job.append(action)

        self.add_to_current_jobs(created_job)

    def add_to_current_jobs(self, created_job: List[Action]):
        """Add the list of actions sent to the jobs window,
            and then perform the actions in the order created.

            Parameters
            ----------
            created_job : List[Action] -
                List of actions that should be performed.
            """
        job = Job(created_job, self.job_index)
        scroll_area_widget = self.jobsScrollAreaWidgetContents
        job_progress_widget = JobProgressWidget(scroll_area_widget,
                                                created_job, self.job_index,
                                                self)
        scroll_layout = self.jobsScrollAreaWidgetContents.layout()
        index_to_add = scroll_layout.count() - 1
        scroll_layout.insertWidget(index_to_add, job_progress_widget)
        self.jobsShownCount.setText(f"{index_to_add}")

        job.signals.job_progress.connect(self.update_job_progress)
        job.signals.job_finished.connect(self.update_job_complete)

        self.job_index = self.job_index + 1
        self.add_new_job(job)

    def add_new_job(self, job: Job):
        """Add a new job to the jobs being displayed, and perform the job.

            Parameters
            ----------
            job : Job -
                The Job that should be performed and displayed.
        """
        self.jobs_threadpool.start(job)
        thread_count = self.jobs_threadpool.activeThreadCount()
        self.activeJobsCount.setText(f"{thread_count}")

    # region PyQt Slots for action progress
    def _get_progress_widget(self,
                             job_index: int,
                             action_index: Optional[int] = None,
                             subaction_index: Optional[int] = None)\
            -> Union[JobProgressWidget,
                     ActionProgressWidget,
                     SubactionProgressWidget]:
        """Get the widget whose progress should be updated,
            based on the indexes sent.

            If an action index or subaction index is not sent,
            sends the main job progress widget.

            Parameters
            ----------
            job_index : int -
                The index of the job progress widget whose
                progress should be updated.\n
            action_index : Optional[int], optional -
                The index of the action progress widget
                whose progress should be updated.
                By default None.\n
            subaction_index : Optional[int], optional -
                The index of the subaction progress widget
                whose progress should be updated.
                By default None.\n

            Returns
            -------
            Union[JobProgressWidget,
            ActionProgressWidget, SubactionProgressWidget] -
                The Widget whose progress should be updated,
                based on the indexes sent.
            """
        job_widget_name = f"JobProgressWidget_{job_index}"
        job_progress_widget = self\
            .jobsScrollAreaWidgetContents.findChild(JobProgressWidget,
                                                    job_widget_name)
        job_progress_widget = cast(JobProgressWidget, job_progress_widget)
        if action_index is None:
            return job_progress_widget

        action_progress_widget = job_progress_widget\
            .actionsScrollAreaWidgetContents.layout()\
            .itemAt(action_index).widget()
        action_progress_widget = cast(ActionProgressWidget,
                                      action_progress_widget)
        if subaction_index is None:
            return action_progress_widget

        subaction_progress_widget = action_progress_widget\
            .subactionsScrollAreaWidgetContents.layout()\
            .itemAt(subaction_index).widget()
        subaction_progress_widget = cast(SubactionProgressWidget,
                                         subaction_progress_widget)
        return subaction_progress_widget

    @pyqtSlot(int, int)
    def update_job_progress(self, job_index: int, progress: int):
        """Update the progress bar of the job that is
            associated with this job index.

            Parameters
            ----------
            job_index : int -
                The index of the job that should be updated.\n
            progress : int -
                The value the progress bar should be updated to.
            """
        job_progress_widget = self._get_progress_widget(job_index)
        job_progress_widget = cast(JobProgressWidget, job_progress_widget)
        job_progress_widget.jobProgressBar.setValue(progress)

    @pyqtSlot(int)
    def update_job_complete(self, job_index: int):
        """Update the progress bar of the job progress widget to be complete,
            and allow a user to remove this job from the list.

            Parameters
            ----------
            job_index : int -
                The index of the job that should be updated.
            """
        job_progress_widget = self._get_progress_widget(job_index)
        job_progress_widget.jobProgressBar\
            .setValue(job_progress_widget.jobProgressBar.maximum())
        job_progress_widget.removeJobButton.setEnabled(True)
        job_progress_widget.removeJobButton.show()
        job_count = self.jobs_threadpool.activeThreadCount()
        self.activeJobsCount.setText(f"{job_count}")

    @pyqtSlot(int, int, int)
    def set_action_length(self, job_index: int, action_index: int,
                          length: int):
        """Set the maximum of the progress bar associated
            with this action to length.

            Parameters
            ----------
            job_index : int -
                The index of the job the action is associated with.\n
            action_index : int -
                The index of this action in the job list.\n
            length : int -
                The value the progress bar should set as the maximum.\n
            """
        action_progress_widget = self._get_progress_widget(
            job_index, action_index)
        action_progress_widget = cast(ActionProgressWidget,
                                      action_progress_widget)
        action_progress_widget.actionProgressBar.setMaximum(length)

    @pyqtSlot(int, int, int)
    def update_action_progress(self, job_index: int, action_index: int,
                               progress: int):
        """Update the progress bar associated with this action
            with the progress sent.

            Parameters
            ----------
            job_index : int -
                The index of the job the action is associated with.\n
            action_index : int -
                The index of the action whose progress bar
                should be updated.\n
            progress : int -
                The value that the progress bar should be set to.
            """
        action_progress_widget = self._get_progress_widget(
            job_index, action_index)
        action_progress_widget = cast(ActionProgressWidget,
                                      action_progress_widget)
        action_progress_widget.actionProgressBar.setValue(progress)

    @pyqtSlot(int, int)
    def update_action_complete(self, job_index: int, action_index: int):
        """Update the progress bar of the action widget to be complete.

            Parameters
            ----------
            job_index : int -
                The index of the job the action is associated with.\n
            action_index : int -
                The index of the action that should be updated.
            """
        action_progress_widget = self._get_progress_widget(
            job_index, action_index)
        action_progress_widget.actionProgressBar\
            .setValue(action_progress_widget.actionProgressBar.maximum())

    @pyqtSlot(int, int, int, int)
    def set_subaction_length(self, job_index: int, action_index: int,
                             subaction_index: int, length: int):
        """Set the max value of the progress bar linked to this subaction.

            Parameters
            ----------
            job_index : int -
                The index of the job linked to this subaction.\n
            action_index : int -
                The index of the action linked to this subaction.\n
            subaction_index : int -
                The index of this subaction in the subactions list.\n
            length : int -
                The value that should be set as the max value.\n
            """
        subaction_progress_widget = self._get_progress_widget(
            job_index, action_index, subaction_index)
        subaction_progress_widget = cast(SubactionProgressWidget,
                                         subaction_progress_widget)
        subaction_progress_widget.subactionProgressBar.setMaximum(length)

    @pyqtSlot(int, int, int, int)
    def update_subaction_progress(self, job_index: int, action_index: int,
                                  subaction_index: int, progress: int):
        """Update the progress bar linked to this subaction
            with the progress value sent.

            Parameters
            ----------
            job_index : int -
                The index of the job linked to this subaction.\n
            action_index : int -
                The index of the action linked to this subaction.\n
            subaction_index : int -
                The index of this subaction in the subactions list.\n
            progress : int -
                The value that the progress bar should be upated to.
            """
        subaction_progress_widget = self._get_progress_widget(
            job_index, action_index, subaction_index)
        subaction_progress_widget = cast(SubactionProgressWidget,
                                         subaction_progress_widget)
        subaction_progress_widget.subactionProgressBar.setValue(progress)

    @pyqtSlot(int, int, int)
    def update_subaction_complete(self, job_index: int, action_index: int,
                                  subaction_index: int):
        """Update the progress bar of this subaction to the max value.

            Parameters
            ----------
            job_index : int -
                The index of the job linked to this subaction.\n
            action_index : int -
                The index of the action linked to this subaction.\n
            subaction_index : int -
                The index of this subaction in the subactions list.
            """
        subaction_progress_widget = self._get_progress_widget(
            job_index, action_index, subaction_index)
        subaction_progress_widget = cast(SubactionProgressWidget,
                                         subaction_progress_widget)
        subaction_progress_widget.subactionProgressBar.setValue(
            subaction_progress_widget.subactionProgressBar.maximum())
Пример #15
0
class CommandExecutionFactory(QThread):
    finish_event = pyqtSignal('PyQt_PyObject', int)
    result_event = pyqtSignal('PyQt_PyObject')

    def __init__(self, runnable_commands, logger=None, max_threads=None):
        super().__init__()
        self.pending_jobs = runnable_commands
        self.total_jobs = len(self.pending_jobs)
        self.completed = []
        self.thread_pool = QThreadPool()
        self.stop = False
        self.logger = logger
        if max_threads:
            self.max_threads = min(max_threads,
                                   self.thread_pool.maxThreadCount())
        else:
            self.max_threads = self.thread_pool.maxThreadCount()

        self.log(f"Multi-threading with maximum of {self.max_threads} threads")

    def add_task(self, task):
        self.pending_jobs.append(task)
        self.total_jobs += 1
        self.run()

    def get_max_threads(self):
        return self.max_threads

    def get_active_thread_count(self):
        return self.thread_pool.activeThreadCount()

    def stop_scan(self):
        self.stop = True

    def run(self):
        self.do_work()

    def thread_complete(self, result):
        self.completed.append(result)
        self.do_work()

    def is_running(self):
        return self.thread_pool.activeThreadCount() > 0

    def do_work(self):
        if len(self.pending_jobs) > 0:
            if self.stop:
                self.log(
                    "Stop has been received. Waiting for threads to finish before exiting..."
                )
                self.thread_pool.waitForDone()
                self.log(
                    f"Waiting for {self.total_jobs - len(self.pending_jobs) - len(self.completed)} "
                    f"threads to finish")
                if (self.total_jobs - len(self.pending_jobs) -
                        len(self.completed)) == 0:
                    self.finish_event.emit(self.completed, sum(self.completed))
                return
            active_threads = self.thread_pool.activeThreadCount()
            available_threads = self.max_threads - active_threads
            for i in range(0, min(available_threads, len(self.pending_jobs))):
                self.log("Dispatching thread on empty slot...")
                runnable = self.pending_jobs.pop()
                runnable.signals.__complete__.connect(self.thread_complete)
                runnable.setAutoDelete(True)
                # Execute
                self.thread_pool.start(runnable)
        else:
            self.log("Waiting for threads to finish")
            if len(self.completed) == self.total_jobs:
                total_time = sum(self.completed)
                self.log(f"Done. Total work completed in...{total_time}")
                self.finish_event.emit(self.completed, total_time)

    def log(self, message):
        if self.logger:
            self.logger.info(message)