def run_process(self, dir, filename, set_item, childIndex): if self.p is None: # No process running. self.p_item = dict(set_item=set_item, child_index=childIndex) self.p = QProcess( ) # Keep a reference to the QProcess (e.g. on self) while it's running. # item # self.p.readyReadStandardOutput.connect(self.handle_stdout) self.p.readyReadStandardError.connect(self.handle_stderr) self.p.stateChanged.connect(self.handle_state) self.p.finished.connect( self.process_finished) # Clean up once complete. # filename = r"J:\Media Library\TV\New\Family Guy\Misc\Family Guy S07E11.avi" filepath = dir + filename self.message("Executing process for file: " + filepath) if Path(filepath).stat().st_size > 0: args = ["-hashfile", filepath, "SHA512"] self.p.start("certutil", args) else: # CertUtil cannot compute hashes on empty files args = ["zero_sha512.py"] self.p.start("python", args) status = set_item.child(childIndex, 0) status.setIcon(self.running_icon) set_item.setIcon(self.running_icon) if status.text() == '': if set_item.text() != 'Test': set_item.child(childIndex, 0).setText('Running Pass 1/3') else: set_item.child(childIndex, 0).setText('Running') elif status.text() == 'Running Pass 1/3': set_item.child(childIndex, 0).setText('Running Pass 2/3') elif status.text() == 'Running Pass 2/3': set_item.child(childIndex, 0).setText('Running Pass 3/3') else: self.message("process already running!")
def item_open_event(self): """ Opens the selected files using xdg-open, runs it, if it is executable or changes the current dir if it's dir. """ selected_items = [] for index in self.table_view.selectedIndexes(): if index.column() == 0: selected_items.append(QFileInfo(os.path.join(self.current_path, index.siblingAtColumn(0).data()))) # warn before accidentally open a bunch of files open = True if len(selected_items) > 3: dialog = utility.question_dialog('Do you really want to open ' + str(len(selected_items)) + ' files?') button = dialog.exec() if button == QMessageBox.Cancel: open = False if open: for item in selected_items: if (item.isDir()): next_path = item.absoluteFilePath() self.update_current_path(next_path) elif (item.isFile()): if (item.isExecutable()): QProcess().startDetached(item.absoluteFilePath(), [], self.current_path) else: QProcess().startDetached('xdg-open', [item.absoluteFilePath()], self.current_path) else: dialog = utility.message_dialog('The type of the selected' + ' file can not be' + ' detected.', QMessageBox.Warning) dialog.exec()
def check_external_program(self, command, args, log, validator=None): process = QProcess() process.start(command, args) process.waitForFinished() output = process.readAllStandardOutput() + process.readAllStandardError() if process.exitCode() == 0: validation_ok = True if validation_ok: log += "<b><font color=\"green\">OK</font></b>" return True, log log += "<font color=\"red\">FAILED</font>" log += "<pre>" log += output log += "</pre>" return False, log
def closeEvent(self, event): if QMessageBox.question(self, "退出程序", "确定退出吗?") == QMessageBox.No: event.ignore() else: event.accept() self.shutdown_aria2.emit() # - [x]: 在线程Thread1跑界面,再在Thread1中开一个进程跑aria2RPC伺服 # - [ ]: 在线程Thread2跑下载,获取下载状态,传递给界面的progressBar(信号与槽) # - [ ]: 在Thread1中用按钮控制Thread2的下载(信号与槽) # >> (It is safe to connect signals and slots across different threads) if __name__ == "__main__": process_aria2 = QProcess() program = "aria2c.exe" arguments = [ '--enable-rpc=true', '--allow-overwrite=false', '--max-overall-download-limit=1M' ] process_aria2.start(program, arguments) app = QApplication() w = MyWidget() dt = DownloadThread([w.lineEditorUrl.text()]) dt.resultReady.connect(w.updateProgress) # w.buttonStart.clicked.connect(dt.download)
def runProcess(command, arguments): process = QProcess() process.start(command, arguments) process.waitForFinished() std_output = process.readAllStandardOutput().data().decode('utf-8') return std_output.split('\n')
class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self): super(MainWindow, self).__init__() #self.ui = () self.setupUi(self) self.p: QProcess = None dirname = r"K:\Media Library" processing_dirs = getBaseDirs(dirname) s: QtCore.QSize = self.treeView.iconSize() self.message(f'size = {s}') s = QtCore.QSize(16, 16) # Set icon sizing here self.treeView.setIconSize(s) style = QApplication.style() self.running_icon = style.standardIcon(QStyle.SP_BrowserReload) self.done_icon = style.standardIcon(QStyle.SP_DialogApplyButton) self.failed_icon = style.standardIcon(QStyle.SP_MessageBoxCritical) self.missing_icon = style.standardIcon( QStyle.SP_TitleBarContextHelpButton) self.added_icon = style.standardIcon(QStyle.SP_ArrowUp) self.warning_icon = style.standardIcon(QStyle.SP_MessageBoxWarning) self.checksum_sets = [] for dirname in processing_dirs: self.checksum_sets.append(ChecksumSet(dirname)) self.updateStats() self.populateModel() self.treeView.setModel(self.model) # self.treeView.setExpandsOnDoubleClick(True) # for x in self.iterItems(self.model.invisibleRootItem()): # y = x.data(role=DisplayRole) # z = x.data(role=UserRole) # self.message(f'y = {y}, z = {z}') # x.setText('hi') # y = x.data(role=QtCore.Qt.UserRole) # self.message(x.text()) # self.message('HI' + y.baseDirname) # self.message('HI' + str(y)) self.start_process() # model.setHorizontalHeaderLabels(['Title', 'Summary']) # rootItem = model.invisibleRootItem() #First top-level row and children # item0 = [QStandardItem('Title0'), QStandardItem('Summary0')] # item00 = [QStandardItem('Title00'), QStandardItem('Summary00')] # item01 = [QStandardItem('Title01'), QStandardItem('Summary01')] # rootItem.appendRow(item0) # item0[0].appendRow(item00) # item0[0].appendRow(item01) #Second top-level item and its children # item1 = [QStandardItem('Title1'), QStandardItem('Summary1')] # item10 = [QStandardItem('Title10'), QStandardItem('Summary10')] # item11 = [QStandardItem('Title11'), QStandardItem('Summary11')] # item12 = [QStandardItem('Title12'), QStandardItem('Summary12')] # rootItem.appendRow(item1) # item1[0].appendRow(item10) # item1[0].appendRow(item11) # item1[0].appendRow(item12) #Children of item11 (third level items) # item110 = [QStandardItem('Title110'), QStandardItem('Summary110')] # item111 = [QStandardItem('Title111'), QStandardItem('Summary111')] # item11[0].appendRow(item110) # item11[0].appendRow(item111) def toast_notification(self, title, text): AppID = 'zchecksum' XML = ToastNotificationManager.get_template_content( ToastTemplateType.TOAST_TEXT02) print(XML) t = XML.get_elements_by_tag_name("text") print(t) t[0].append_child(XML.create_text_node(title)) t[1].append_child(XML.create_text_node(text)) notifier = ToastNotificationManager.create_toast_notifier(AppID) notifier.show(ToastNotification(XML)) def iterItems(self, root): if root is not None: for row in range(root.rowCount()): row_item = root.child(row, 0) if row_item.hasChildren(): for childIndex in range(row_item.rowCount()): # Take second column from "child"-row child = row_item.child(childIndex, 1) yield child def format_size(self, size): if size < 0: raise Exception('Unknown file size') if size < 1024: return f'{size} Bytes' elif size < 1024 * 1024: size_kb = size / 1024 return f'{size_kb:.1f} KB' elif size < 1024 * 1024 * 1024: size_mb = size / 1024 / 1024 return f'{size_mb:.1f} MB' else: size_gb = size / 1024 / 1024 / 1024 return f'{size_gb:.1f} GB' def populateModel(self): self.model = QStandardItemModel() self.model.setHorizontalHeaderLabels([ 'Status', 'Directory / Filename', 'File Count', 'Size', 'Checksum', 'Last Verified' ]) rootItem = self.model.invisibleRootItem() for checksum_set in self.checksum_sets: last_verified = '' status = '' if not checksum_set.hasSha512File(): status = 'New' elif checksum_set.has_changes(): status = "Modified" self.toast_notification("Checksum set was modified.", checksum_set.baseDirname) else: time_delta = datetime.now( ) - checksum_set.sha512File.last_verified last_verified = f'{time_delta.days} days ago' if time_delta.days > good_days: status = 'Test' else: status = 'Good' if status == 'Test' or status == 'New' or status == 'Modified': item = [ QStandardItem(status), QStandardItem(checksum_set.baseDirname), QStandardItem(str(len(checksum_set.filenames))), QStandardItem(''), QStandardItem(''), QStandardItem(last_verified) ] for filename in checksum_set.filenames: checksum_text = '' file_status = '' if checksum_set.sha512File: checksum = checksum_set.sha512File.findChecksum( filename) if checksum: checksum_text = checksum else: file_status = 'Added' size = Path(checksum_set.baseDirname + filename).stat().st_size size_display = self.format_size(size) # sz = len(checksum_set.baseDirname) + len(filename) c_item = [ QStandardItem(file_status), QStandardItem(filename), QStandardItem(''), QStandardItem(size_display), QStandardItem(checksum_text) ] c_item[1].setData(checksum_set, QtCore.Qt.UserRole) if file_status == 'Added': c_item[0].setIcon(self.added_icon) if filename == 'Thumbs.db': c_item[0].setIcon(self.warning_icon) item[0].appendRow(c_item) if checksum_set.hasSha512File(): for filename in checksum_set.get_missing_from_dir(): checksum_text = checksum_set.sha512File.findChecksum( filename) c_item = [ QStandardItem('Missing'), QStandardItem(filename), QStandardItem(''), QStandardItem('n/a'), QStandardItem(checksum_text) ] c_item[1].setData(checksum_set, QtCore.Qt.UserRole) c_item[0].setIcon(self.missing_icon) item[0].appendRow(c_item) rootItem.appendRow(item) # self.showIssues() #TODO: FIX, NOT WORKING! def showIssues(self): self.treeView.expandAll() root = self.model.invisibleRootItem() if root is not None: for row in range(root.rowCount()): row_item = root.child(row, 0) if row_item.hasChildren(): for childIndex in range(row_item.rowCount()): # Take second column from "child"-row child = row_item.child(childIndex, 1) filename = child.text() print(f'f = {filename}, {row_item.index()}') if filename == 'Thumbs.db': self.treeView.setExpanded(row_item.index(), True) # c_item[0].setIcon(self.warning_icon) # item[0].setExpanded(True) # self.start_process() # header = self.treeWidget.header() # header # header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents) # header.setStretchLastSection(False) # header.setSectionResizeMode(5, QtWidgets.QHeaderView.Stretch) def updateStats(self): new_count = 0 modified_count = 0 test_count = 0 good_count = 0 # items = [] for checksum_set in self.checksum_sets: if not checksum_set.hasSha512File(): new_count += 1 elif checksum_set.has_changes(): modified_count += 1 else: time_delta = datetime.now( ) - checksum_set.sha512File.last_verified if time_delta.days > good_days: test_count += 1 else: good_count += 1 self.statusBar().showMessage( f'Total sets: {len(self.checksum_sets)} sets. New sets: {new_count} Modified sets: {modified_count} Test sets: {test_count} Good sets: {good_count}' ) def message(self, s): # self.statusBar().showMessage(s) self.listWidget.addItem(s) def start_process(self): root = self.model.invisibleRootItem() started_count = 0 if root is not None: for row in range(root.rowCount()): if self.p: break row_item = root.child(row, 0) # item = self.model.item(row) dir = root.child(row, 1) set_status = root.child(row, 0) # self.message(dir.text()) if (set_status.text() == "New" or set_status.text() == 'Test') and row_item.hasChildren(): for childIndex in range(row_item.rowCount()): # Take second column from "child"-row # status = row_item.child(childIndex, 0) # self.message(status.text()) # if status.text() == 'New': # self.message(dir.text()) status = row_item.child(childIndex, 0) filename = row_item.child(childIndex, 1) # self.message(filename.text()) # checksum_item = row_item.child(childIndex, 4) if status.text() != "Done": # parent = filename.parent() # self.message("parent " + str(parent)) self.run_process(dir.text(), filename.text(), row_item, childIndex) started_count += 1 if self.p: break self.message(f'start_process done. Started {started_count}') # yield child # for i in range(self.model.rowCount()): # item = self.model.item(i) # root = self.treeWidget.invisibleRootItem() # child_count = root.childCount() # for i in range(child_count): # item = ro # ot.child(i) # url = item.text(0) # text at first (0) column # item.setText(1, 'result from %s' % url) # update result column (1) def run_process(self, dir, filename, set_item, childIndex): if self.p is None: # No process running. self.p_item = dict(set_item=set_item, child_index=childIndex) self.p = QProcess( ) # Keep a reference to the QProcess (e.g. on self) while it's running. # item # self.p.readyReadStandardOutput.connect(self.handle_stdout) self.p.readyReadStandardError.connect(self.handle_stderr) self.p.stateChanged.connect(self.handle_state) self.p.finished.connect( self.process_finished) # Clean up once complete. # filename = r"J:\Media Library\TV\New\Family Guy\Misc\Family Guy S07E11.avi" filepath = dir + filename self.message("Executing process for file: " + filepath) if Path(filepath).stat().st_size > 0: args = ["-hashfile", filepath, "SHA512"] self.p.start("certutil", args) else: # CertUtil cannot compute hashes on empty files args = ["zero_sha512.py"] self.p.start("python", args) status = set_item.child(childIndex, 0) status.setIcon(self.running_icon) set_item.setIcon(self.running_icon) if status.text() == '': if set_item.text() != 'Test': set_item.child(childIndex, 0).setText('Running Pass 1/3') else: set_item.child(childIndex, 0).setText('Running') elif status.text() == 'Running Pass 1/3': set_item.child(childIndex, 0).setText('Running Pass 2/3') elif status.text() == 'Running Pass 2/3': set_item.child(childIndex, 0).setText('Running Pass 3/3') else: self.message("process already running!") def handle_stderr(self): data = self.p.readAllStandardError() stderr = bytes(data).decode("utf8") # Extract progress if it is in the data. # progress = simple_percent_parser(stderr) # if progress: # self.progress.setValue(progress) self.message(stderr) def handle_stdout(self): data = self.p.readAllStandardOutput() stdout = bytes(data).decode("utf8") self.message(stdout) def handle_state(self, state): states = { QProcess.NotRunning: 'Not running', QProcess.Starting: 'Starting', QProcess.Running: 'Running', } state_name = states[state] self.message(f"State changed: {state_name}") def process_finished(self, exitCode, exitStatus): row_item = self.p_item['set_item'] child_index = self.p_item['child_index'] status_item = row_item.child(child_index, 0) filename_item = row_item.child(child_index, 1) try: checksum_set = filename_item.data(QtCore.Qt.UserRole) if checksum_set is None: self.toast_notification( "Checksum set not found.", "No checksum set for file " + filename_item.text()) raise Exception("No checksum set found") self.message( f'Process finished. exitCode = {exitCode}, exitStatus = {exitStatus}, baseDirname = {checksum_set.baseDirname}' ) data = self.p.readAllStandardOutput() # stdout = bytes(data) # self.message("normal stdout: " + stdout) # .decode('iso-8859-1').encode('utf8') # stdout = bytes(data).decode("iso-8859-1") #try: stdout = bytes(data).decode('utf8', 'replace') # except: # stdout = bytes(data).decode('iso-8859-1') # self.message("row_item" + row_item) self.message("stdout: " + stdout) lines = stdout.splitlines() if exitCode != 0 or len(lines) != 3: msg = f'Compute SHA512 failed. stdout: ({stdout})' error_message = '' if len(lines) > 1 and lines[1].startswith("CertUtil: "): error_message = lines[1][10:] # msg = f'Error: Compute SHA512 failed for file {filename}. stdout: ({cp.stdout}) stderr: ({cp.stderr})' # print(msg) self.toast_notification( 'Failed to compute checksum. ' + error_message, filename_item.text()) raise Exception(msg) new_checksum = lines[1].replace(" ", "") checksum_item = row_item.child(child_index, 4) old_checksum = checksum_item.text() if old_checksum == "": checksum_item.setText(new_checksum) elif new_checksum != old_checksum: msg = f'Checksums do not match.' self.toast_notification('Checksums mismatch', filename_item.text()) raise Exception(msg) if status_item.text() == "Running Pass 3/3" or status_item.text( ) == 'Running': status_item.setText('Done') status_item.setIcon(self.done_icon) # checksum = QStandardItem() # row_item.setChild(0, 4, checksum) # my_item.setText() # my_item.setText(0, "Done") # self.message("my_item: " + my_item.text(1)) # if self.all_files_done_checksum(row_item.parent()): # self.create_sha_file(my_item.parent()) if self.all_files_done_checksum(row_item): row_item.setIcon(self.done_icon) row_item.setText("Done") if checksum_set.hasSha512File(): self.message( f'Updating {checksum_set.baseDirname} checksum file modified date' ) checksum_set.update_modified() else: self.create_sha_file(row_item) except Exception as e: status_item.setText("Failed") status_item.setIcon(self.failed_icon) row_item.setText("Failed") row_item.setIcon(self.failed_icon) self.message("Error: " + str(e)) finally: self.p = None self.start_process() def all_files_done_checksum(self, set_item): for childIndex in range(set_item.rowCount()): status_item = set_item.child(childIndex, 0) checksum_item = set_item.child(childIndex, 4) filename_item = set_item.child(childIndex, 1) self.message(filename_item.text()) if status_item.text() != 'Done' or checksum_item.text() == '': return False return True def create_sha_file(self, set_item): self.message("create_sha_file!!") # index = set_item.index() # self.message(f'index = {index}') # dirname = self.model.item(index, 1) # dirname = set_item.data(1) dir = self.model.invisibleRootItem().child(set_item.row(), 1) dirname = dir.text() self.message( f'create_sha_file2, dir = {dir.text()}, row = {set_item.row()}, set_item.columnCount = {set_item.columnCount()}' ) shaFile = Sha512(dirname) for childIndex in range(set_item.rowCount()): checksum_item = set_item.child(childIndex, 4) filename_item = set_item.child(childIndex, 1) self.message(filename_item.text()) shaFile.addFileAndChecksum(filename_item.text(), checksum_item.text()) shaFile.writeFile()
def __init__(self, parent=None): super(MainWindow, self).__init__() self.statusBar().showMessage("Move Dial to Deform Microphone Voice !.") self.setWindowTitle(__doc__) self.setMinimumSize(240, 240) self.setMaximumSize(480, 480) self.resize(self.minimumSize()) self.setWindowIcon(QIcon.fromTheme("audio-input-microphone")) self.tray = QSystemTrayIcon(self) self.center() QShortcut("Ctrl+q", self, activated=lambda: self.close()) self.menuBar().addMenu("&File").addAction("Quit", lambda: exit()) self.menuBar().addMenu("Sound").addAction( "STOP !", lambda: call('killall rec', shell=True)) windowMenu = self.menuBar().addMenu("&Window") windowMenu.addAction("Hide", lambda: self.hide()) windowMenu.addAction("Minimize", lambda: self.showMinimized()) windowMenu.addAction("Maximize", lambda: self.showMaximized()) windowMenu.addAction("Restore", lambda: self.showNormal()) windowMenu.addAction("FullScreen", lambda: self.showFullScreen()) windowMenu.addAction("Center", lambda: self.center()) windowMenu.addAction("Top-Left", lambda: self.move(0, 0)) windowMenu.addAction("To Mouse", lambda: self.move_to_mouse_position()) # widgets group0 = QGroupBox("Voice Deformation") self.setCentralWidget(group0) self.process = QProcess(self) self.process.error.connect( lambda: self.statusBar().showMessage("Info: Process Killed", 5000)) self.control = QDial() self.control.setRange(-10, 20) self.control.setSingleStep(5) self.control.setValue(0) self.control.setCursor(QCursor(Qt.OpenHandCursor)) self.control.sliderPressed.connect( lambda: self.control.setCursor(QCursor(Qt.ClosedHandCursor))) self.control.sliderReleased.connect( lambda: self.control.setCursor(QCursor(Qt.OpenHandCursor))) self.control.valueChanged.connect( lambda: self.control.setToolTip(f"<b>{self.control.value()}")) self.control.valueChanged.connect(lambda: self.statusBar().showMessage( f"Voice deformation: {self.control.value()}", 5000)) self.control.valueChanged.connect(self.run) self.control.valueChanged.connect(lambda: self.process.kill()) # Graphic effect self.glow = QGraphicsDropShadowEffect(self) self.glow.setOffset(0) self.glow.setBlurRadius(99) self.glow.setColor(QColor(99, 255, 255)) self.control.setGraphicsEffect(self.glow) self.glow.setEnabled(False) # Timer to start self.slider_timer = QTimer(self) self.slider_timer.setSingleShot(True) self.slider_timer.timeout.connect(self.on_slider_timer_timeout) # an icon and set focus QLabel(self.control).setPixmap( QIcon.fromTheme("audio-input-microphone").pixmap(32)) self.control.setFocus() QVBoxLayout(group0).addWidget(self.control) self.menu = QMenu(__doc__) self.menu.addAction(__doc__).setDisabled(True) self.menu.setIcon(self.windowIcon()) self.menu.addSeparator() self.menu.addAction( "Show / Hide", lambda: self.hide() if self.isVisible() else self.showNormal()) self.menu.addAction("STOP !", lambda: call('killall rec', shell=True)) self.menu.addSeparator() self.menu.addAction("Quit", lambda: exit()) self.tray.setContextMenu(self.menu) self.make_trayicon()
class MainWindow(QMainWindow): """Voice Changer main window.""" def __init__(self, parent=None): super(MainWindow, self).__init__() self.statusBar().showMessage("Move Dial to Deform Microphone Voice !.") self.setWindowTitle(__doc__) self.setMinimumSize(240, 240) self.setMaximumSize(480, 480) self.resize(self.minimumSize()) self.setWindowIcon(QIcon.fromTheme("audio-input-microphone")) self.tray = QSystemTrayIcon(self) self.center() QShortcut("Ctrl+q", self, activated=lambda: self.close()) self.menuBar().addMenu("&File").addAction("Quit", lambda: exit()) self.menuBar().addMenu("Sound").addAction( "STOP !", lambda: call('killall rec', shell=True)) windowMenu = self.menuBar().addMenu("&Window") windowMenu.addAction("Hide", lambda: self.hide()) windowMenu.addAction("Minimize", lambda: self.showMinimized()) windowMenu.addAction("Maximize", lambda: self.showMaximized()) windowMenu.addAction("Restore", lambda: self.showNormal()) windowMenu.addAction("FullScreen", lambda: self.showFullScreen()) windowMenu.addAction("Center", lambda: self.center()) windowMenu.addAction("Top-Left", lambda: self.move(0, 0)) windowMenu.addAction("To Mouse", lambda: self.move_to_mouse_position()) # widgets group0 = QGroupBox("Voice Deformation") self.setCentralWidget(group0) self.process = QProcess(self) self.process.error.connect( lambda: self.statusBar().showMessage("Info: Process Killed", 5000)) self.control = QDial() self.control.setRange(-10, 20) self.control.setSingleStep(5) self.control.setValue(0) self.control.setCursor(QCursor(Qt.OpenHandCursor)) self.control.sliderPressed.connect( lambda: self.control.setCursor(QCursor(Qt.ClosedHandCursor))) self.control.sliderReleased.connect( lambda: self.control.setCursor(QCursor(Qt.OpenHandCursor))) self.control.valueChanged.connect( lambda: self.control.setToolTip(f"<b>{self.control.value()}")) self.control.valueChanged.connect(lambda: self.statusBar().showMessage( f"Voice deformation: {self.control.value()}", 5000)) self.control.valueChanged.connect(self.run) self.control.valueChanged.connect(lambda: self.process.kill()) # Graphic effect self.glow = QGraphicsDropShadowEffect(self) self.glow.setOffset(0) self.glow.setBlurRadius(99) self.glow.setColor(QColor(99, 255, 255)) self.control.setGraphicsEffect(self.glow) self.glow.setEnabled(False) # Timer to start self.slider_timer = QTimer(self) self.slider_timer.setSingleShot(True) self.slider_timer.timeout.connect(self.on_slider_timer_timeout) # an icon and set focus QLabel(self.control).setPixmap( QIcon.fromTheme("audio-input-microphone").pixmap(32)) self.control.setFocus() QVBoxLayout(group0).addWidget(self.control) self.menu = QMenu(__doc__) self.menu.addAction(__doc__).setDisabled(True) self.menu.setIcon(self.windowIcon()) self.menu.addSeparator() self.menu.addAction( "Show / Hide", lambda: self.hide() if self.isVisible() else self.showNormal()) self.menu.addAction("STOP !", lambda: call('killall rec', shell=True)) self.menu.addSeparator() self.menu.addAction("Quit", lambda: exit()) self.tray.setContextMenu(self.menu) self.make_trayicon() def run(self): """Run/Stop the QTimer.""" if self.slider_timer.isActive(): self.slider_timer.stop() self.glow.setEnabled(True) call('killall rec ; killall play', shell=True) self.slider_timer.start(3000) def on_slider_timer_timeout(self): """Run subprocess to deform voice.""" self.glow.setEnabled(False) value = int(self.control.value()) * 100 command = f'play -q -V0 "|rec -q -V0 -n -d -R riaa bend pitch {value} "' print(f"Voice Deformation Value: {value}") print(f"Voice Deformation Command: {command}") self.process.start(command) if self.isVisible(): self.statusBar().showMessage("Minimizing to System TrayIcon", 3000) print("Minimizing Main Window to System TrayIcon now...") sleep(3) self.hide() def center(self): """Center Window on the Current Screen,with Multi-Monitor support.""" window_geometry = self.frameGeometry() mousepointer_position = QApplication.desktop().cursor().pos() screen = QApplication.desktop().screenNumber(mousepointer_position) centerPoint = QApplication.desktop().screenGeometry(screen).center() window_geometry.moveCenter(centerPoint) self.move(window_geometry.topLeft()) def move_to_mouse_position(self): """Center the Window on the Current Mouse position.""" window_geometry = self.frameGeometry() window_geometry.moveCenter(QApplication.desktop().cursor().pos()) self.move(window_geometry.topLeft()) def make_trayicon(self): """Make a Tray Icon.""" if self.windowIcon() and __doc__: self.tray.setIcon(self.windowIcon()) self.tray.setToolTip(__doc__) self.tray.activated.connect( lambda: self.hide() if self.isVisible() else self.showNormal()) return self.tray.show()
def __init__(self, parent=None) -> None: super().__init__(parent) self.verticalLayout = QVBoxLayout(self) self.compileButton = QPushButton('Compile', self) self.compileButton.setMinimumSize(QSize(200, 50)) self.verticalLayout.addWidget(self.compileButton, 0, Qt.AlignHCenter) self.tidyButton = QPushButton('Tidy', self) self.verticalLayout.addWidget(self.tidyButton, 0, Qt.AlignHCenter) self.splitter = QSplitter(self) self.splitter.setOrientation(Qt.Vertical) self.widget = QWidget(self.splitter) self.widget.setObjectName(u"widget") self.verticalLayout2 = QVBoxLayout(self.widget) self.stdoutLabel = QLabel(self.widget) self.stdoutLabel.setText('stdout:') self.verticalLayout2.addWidget(self.stdoutLabel) self.stdoutText = QTextEdit(self.widget) self.stdoutText.setEnabled(False) self.stdoutText.setReadOnly(True) self.stdoutText.setPlainText("Output will appear here") self.verticalLayout2.addWidget(self.stdoutText) self.splitter.addWidget(self.widget) self.widget1 = QWidget(self.splitter) self.verticalLayout3 = QVBoxLayout(self.widget1) self.stderrLabel = QLabel(self.widget1) self.stderrLabel.setText('stderr:') self.verticalLayout3.addWidget(self.stderrLabel) self.stderrText = QTextEdit(self.widget1) self.stderrText.setEnabled(False) self.stderrText.setReadOnly(True) self.stderrText.setPlainText('Errors will appear here') self.verticalLayout3.addWidget(self.stderrText) self.splitter.addWidget(self.widget1) self.verticalLayout.addWidget(self.splitter) # Logic # Use QProcess to start a program and get its outputs https://stackoverflow.com/a/22110924 self.process = QProcess(self) self.process.readyReadStandardOutput.connect(self.readStdout) self.process.readyReadStandardError.connect(self.readStderr) self.process.started.connect(self.processStarted) self.process.finished.connect(self.processFinished) self.process.errorOccurred.connect(self.errorOccurred) self.compileButton.clicked.connect(self.doCompile) self.tidyButton.clicked.connect(self.doTidy)
class BuilderWidget(QWidget): def __init__(self, parent=None) -> None: super().__init__(parent) self.verticalLayout = QVBoxLayout(self) self.compileButton = QPushButton('Compile', self) self.compileButton.setMinimumSize(QSize(200, 50)) self.verticalLayout.addWidget(self.compileButton, 0, Qt.AlignHCenter) self.tidyButton = QPushButton('Tidy', self) self.verticalLayout.addWidget(self.tidyButton, 0, Qt.AlignHCenter) self.splitter = QSplitter(self) self.splitter.setOrientation(Qt.Vertical) self.widget = QWidget(self.splitter) self.widget.setObjectName(u"widget") self.verticalLayout2 = QVBoxLayout(self.widget) self.stdoutLabel = QLabel(self.widget) self.stdoutLabel.setText('stdout:') self.verticalLayout2.addWidget(self.stdoutLabel) self.stdoutText = QTextEdit(self.widget) self.stdoutText.setEnabled(False) self.stdoutText.setReadOnly(True) self.stdoutText.setPlainText("Output will appear here") self.verticalLayout2.addWidget(self.stdoutText) self.splitter.addWidget(self.widget) self.widget1 = QWidget(self.splitter) self.verticalLayout3 = QVBoxLayout(self.widget1) self.stderrLabel = QLabel(self.widget1) self.stderrLabel.setText('stderr:') self.verticalLayout3.addWidget(self.stderrLabel) self.stderrText = QTextEdit(self.widget1) self.stderrText.setEnabled(False) self.stderrText.setReadOnly(True) self.stderrText.setPlainText('Errors will appear here') self.verticalLayout3.addWidget(self.stderrText) self.splitter.addWidget(self.widget1) self.verticalLayout.addWidget(self.splitter) # Logic # Use QProcess to start a program and get its outputs https://stackoverflow.com/a/22110924 self.process = QProcess(self) self.process.readyReadStandardOutput.connect(self.readStdout) self.process.readyReadStandardError.connect(self.readStderr) self.process.started.connect(self.processStarted) self.process.finished.connect(self.processFinished) self.process.errorOccurred.connect(self.errorOccurred) self.compileButton.clicked.connect(self.doCompile) self.tidyButton.clicked.connect(self.doTidy) def doCompile(self): self.cleanupUI() self.process.setWorkingDirectory(settings.get_repo_location()) self.process.startCommand(settings.get_build_command()) def doTidy(self): self.cleanupUI() self.process.setWorkingDirectory(settings.get_repo_location()) self.process.startCommand(settings.get_tidy_command()) def cleanupUI(self): self.stdoutText.setEnabled(True) self.stderrText.setEnabled(True) self.stdoutText.setPlainText('') self.stderrText.setPlainText('') def readStdout(self): lines = self.process.readAllStandardOutput().data().decode( )[:-1].split('\n') for line in lines: if line == 'tmc.gba: FAILED': line = 'tmc.gba: <b style="color:red">FAILED</b>' elif line == 'tmc.gba: OK': line = 'tmc.gba: <b style="color:lime">OK</b>' self.stdoutText.append(line) def readStderr(self): lines = self.process.readAllStandardError().data().decode()[:-1].split( '\n') for line in lines: if 'error' in line.lower(): line = f'<span style="color:red">{line}</span>' elif 'warning' in line.lower(): line = f'<span style="color:orange">{line}</span>' self.stderrText.append(line) def processStarted(self): self.compileButton.setEnabled(False) self.tidyButton.setEnabled(False) def processFinished(self): self.compileButton.setEnabled(True) self.tidyButton.setEnabled(True) def errorOccurred(self): self.stderrText.insertPlainText(self.process.errorString())
def parse_asn1(*files, **options): ''' Call the ASN.1 parser on a number of files, and return the module containing the AST This function uses QProcess to launch the ASN.1 compiler because the subprocess module from Python has issues on the Windows platform ''' if '-g' in sys.argv: os.environ["PROJECT_CACHE"] = './debug' # use basic caching to avoid re-parsing when loading the model project_cache = os.getenv("PROJECT_CACHE") if project_cache is not None and not os.path.isdir(project_cache): try: print(f"[INFO] Creating cache folder {project_cache}") os.makedirs(project_cache) except OSError: raise TypeError( f'''The configured cache folder "{project_cache} " \ is not there and could not be created\n''') # make sure the same files are not parsed more than once if not modified filehash = hashlib.md5() file_list = sorted(list(*files)) try: for each in file_list: filehash.update(open(each).read().encode('utf-8')) # also hash the file path: it is used in the AST, so it is # not enough to hash the content of the ASN.1 files, as two sets # of input files may have the same hash filehash.update(each.encode('utf-8')) except IOError as err: raise TypeError(str(err)) new_hash = filehash.hexdigest() # names of the files that will be generated by asn1scc and then parsed out_py_name = new_hash + ".py" out_html_name = new_hash + ".html" if new_hash in AST.keys(): return AST[new_hash] elif project_cache is not None: outdir = project_cache elif project_cache is None: outdir = tempfile.mkdtemp() # to allow the import sys.path.append(outdir) ast_version = options.get('ast_version', ASN1.UniqueEnumeratedNames) rename_policy = options.get('rename_policy', ASN1.NoRename) flags = options.get('flags', [ASN1.AstOnly]) pprint = options.get('pretty_print', False) extraflags = options.get('extraflags', []) assert isinstance(ast_version, ASN1) assert isinstance(rename_policy, ASN1) assert isinstance(flags, list) path_to_asn1scc = spawn.find_executable('asn1scc') if not path_to_asn1scc: raise TypeError('ASN.1 Compiler (asn1scc) not found in path') binary = path_to_asn1scc asn1scc_root = os.path.abspath(os.path.dirname(binary)) if os.name == 'nt': # On windows, remove the drive letter, workaround to ASN1SCC bug outdir = outdir[2:] asn1scc_root = asn1scc_root[2:] # The two possible files that can be generated with complete path: py_filepath = outdir + os.sep + out_py_name html_filepath = outdir + os.sep + out_html_name # call the ASN.1 compiler only if there is no existing cached file if project_cache is None or not os.path.exists(py_filepath): stg = asn1scc_root + os.sep + 'python.stg' if pprint: # Generate an html file with pretty-printed ASN.1 types stg_qrc = QFile(':misc/pretty_print_asn1.stg') stg_qrc.open(QIODevice.ReadOnly) content = stg_qrc.readAll() stgfile = outdir + os.sep + 'pretty_print_asn1.stg' with open(stgfile, 'wb') as tmpfile: tmpfile.write(content.data()) html = ['-customIcdUper', stgfile + '::' + html_filepath] else: html = [] args = [ '-customStgAstVersion', str(ast_version.value), '--field-prefix', 'AUTO', '-customStg', stg + '::' + py_filepath, '-renamePolicy', str(rename_policy.value) ] + html + extraflags + file_list asn1scc = QProcess() LOG.debug(os.getcwd()) LOG.debug(args) LOG.debug(binary + ' ' + ' '.join(args)) LOG.debug(f"Python AST: {py_filepath}") asn1scc.start(binary, args) _ = waitfor_qprocess(asn1scc, "ASN.1 Compiler") ast = importlib.import_module(new_hash) AST[new_hash] = ast if pprint: # add the path to the optionally-generated pretty-printed HTML file ast.html = html_filepath return ast
def asn2dataModel(files, outdir=None, db=None): ''' Call asn2dataModel, including the Makefile.python and return the imported module "name_of_dataview_asn.py" From this module it is possible to create native Asn1scc instances of ASN.1 data types, and to access to DV.py, which contains constants such as the _PRESENT fields for choice selectors. In addition the SqlAlchemy interface is also imported give db a name to create the database if outdir is none, a temporary folder will be used ''' assert len(files) > 0 # 1) Create a temporary directory for the output if '-g' in sys.argv: # In debug mode, don't hide the files in /tmp os.makedirs('./debug', exist_ok=True) tempdir = './debug/' elif outdir is None: tempdir = tempfile.mkdtemp() else: os.makedirs(outdir, exist_ok=True) tempdir = outdir sys.path.insert(0, tempdir) # Use a unique name for the asn1 concatenated module # concat_prefix = str(uuid.uuid4()).replace('-', '_') # Update MP 19/01/2022 - why use a unique name while # we are already in a random temp folder? concat_prefix = 'og_dataview' concat_path = os.path.join(tempdir, concat_prefix) concat_file = concat_path + '.asn' if os.path.exists(concat_file): concat_timestamp = os.path.getctime(concat_file) else: concat_timestamp = 0 # 2) Concat all input files to the output directory # if any of the files is more recent that the # existing concatenated file cat_bin = spawn.find_executable('cat') args = files # list timestamps = [] for each in args: timestamps.append(os.path.getmtime(each)) if any(ts > concat_timestamp for ts in timestamps): cat = QProcess() LOG.debug(os.getcwd()) LOG.debug(cat_bin + ' ' + ' '.join(args)) cat.start(cat_bin, args) merged = waitfor_qprocess(cat, 'Merge dataviews') with open(concat_path + '.asn', 'wt') as merged_file: merged_file.write(merged.data().decode('utf-8')) # 3) Run asn2dataModel for Python asn2dm_bin = spawn.find_executable('asn2dataModel') args = ['-toPython', '-o', tempdir, concat_path + '.asn'] asn2dm = QProcess() LOG.debug(os.getcwd()) LOG.debug(asn2dm_bin + ' ' + ' '.join(args)) asn2dm.start(asn2dm_bin, args) waitfor_qprocess(asn2dm, 'DMT tool "asn2dataModel"') # 4) call make -f Makefile.python to build the .so make_bin = spawn.find_executable('make') args = ['-f', 'Makefile.python'] make = QProcess() make.setWorkingDirectory(tempdir) LOG.debug(os.getcwd()) LOG.debug(make_bin + ' ' + ' '.join(args)) make.start(make_bin, args) waitfor_qprocess(make, 'make -f Makefile.python') # 5) Run asn2dataModel for the SQL Alchemy module args = ['-toSqlalchemy', '-o', tempdir, concat_path + '.asn'] asn2dm = QProcess() LOG.debug(os.getcwd()) LOG.debug(asn2dm_bin + ' ' + ' '.join(args)) asn2dm.start(asn2dm_bin, args) waitfor_qprocess(asn2dm, 'DMT tool "asn2dataModel"') else: LOG.info("Reusing DMT outputs from previous run") if concat_prefix in ASN2DM.keys(): # Re-import module if it was already loaded asn1mod = ASN2DM[concat_prefix] dbmod = asn1mod.db_model importlib.reload(asn1mod) importlib.reload(asn1mod.DV) importlib.reload(dbmod) asn1mod.db_model = dbmod import Stubs importlib.reload(Stubs) else: asn1mod = importlib.import_module(concat_prefix + '_asn') # force reload of modules in case of multiple calls importlib.reload(asn1mod.DV) import Stubs importlib.reload(Stubs) # Add the SQL Alchemy module interface import db_model asn1mod.db_model = db_model ASN2DM[concat_prefix] = asn1mod # 6) Create the database is "db" is set if db is not None: # db should be e.g. "sqlite:///file.sqlite" from sqlalchemy import create_engine from db_model import Base engine = create_engine(db, echo=False) Base.metadata.create_all(engine) sys.path.pop(0) return asn1mod