def send_requests(self, pgn, mid=234): total_requests = 3 * (len(self.root.source_addresses) + 1) progress = QProgressDialog(self) progress.setMinimumWidth(600) progress.setWindowTitle("Requesting Vehicle Network Messages") progress.setMinimumDuration(0) #progress.setWindowModality(Qt.WindowModal) # Improves stability of program progress.setModal(False) progress.setMaximum(total_requests) request_count = 1 for i in range(3): self.root.send_j1587_request(mid) sa_list = [0xff] + self.root.source_addresses random.shuffle(sa_list) for sa in sa_list: if self.root.find_j1939_data(pgn, sa): break if progress.wasCanceled(): break self.root.send_j1939_request(pgn, sa) time.sleep(0.1 + 0.1 * random.random()) request_count += 1 progress.setValue(request_count) QCoreApplication.processEvents() progress.deleteLater() self.rebuild_trees()
def waitForSignal(signal, message="", timeout=0): """Waits (max timeout msecs if given) for a signal to be emitted. It the waiting lasts more than 2 seconds, a progress dialog is displayed with the message. Returns True if the signal was emitted. Return False if the wait timed out or the dialog was canceled by the user. """ loop = QEventLoop() dlg = QProgressDialog(minimum=0, maximum=0, labelText=message) dlg.setWindowTitle(appinfo.appname) dlg.setWindowModality(Qt.ApplicationModal) QTimer.singleShot(2000, dlg.show) dlg.canceled.connect(loop.quit) if timeout: QTimer.singleShot(timeout, dlg.cancel) stop = lambda: loop.quit() signal.connect(stop) loop.exec_() signal.disconnect(stop) dlg.hide() dlg.deleteLater() return not dlg.wasCanceled()
def waitForSignal(signal, message="", timeout=0): """Waits (max timeout msecs if given) for a signal to be emitted. It the waiting lasts more than 2 seconds, a progress dialog is displayed with the message. Returns True if the signal was emitted. Return False if the wait timed out or the dialog was canceled by the user. """ loop = QEventLoop() dlg = QProgressDialog(minimum=0, maximum=0, labelText=message) dlg.setWindowTitle(appinfo.appname) dlg.setWindowModality(Qt.ApplicationModal) QTimer.singleShot(2000, dlg.show) dlg.canceled.connect(loop.quit) if timeout: QTimer.singleShot(timeout, dlg.cancel) stop = lambda: loop.quit() signal.connect(stop) loop.exec_() signal.disconnect(stop) dlg.hide() dlg.deleteLater() return not dlg.wasCanceled()
def on_pb_downloadPerson_clicked(self): '''方法作用从住建平台上下载已生成了住建平台号的人员信息''' runStatus = True progress = QProgressDialog(self) progress.setWindowTitle('请稍等') progress.setLabelText('数据下载中...') progress.setCancelButtonText('中止操作') progress.setWindowModality(Qt.WindowModal) progress.resize(800, 50) while runStatus: countD = self.faceDevices.rowCount() progress.setRange(0, countD) if countD > 0: i = 0 while i < countD: faces = self.faceDevices.record(i) sn = str.strip(faces.field('sn').value()) key = str.strip(faces.field('key').value()) self.cdzj.downloadPerson(sn, key) if self.cdzj.msg_downloadPerson == 'success': qs = "update wis_person set user_id = '%s', work_sn = '%s' where idNo = '%s'" % ( self.cdzj.person['user_id'], self.cdzj.person['work_sn'], self.cdzj.person['idNo']) self.db.excuteSQl(qs) selectQs = "select * from wis_person where idNo = '%s'" % self.cdzj.person[ 'idNo'] data = self.db.querySQL(selectQs) countP = data.rowCount() self.cdzj.feedback(sn, 2, '下发成功') progress.setValue(i) if progress.wasCanceled(): QMessageBox.warning(self, "提示", "操作失败") break # QMessageBox.information(self, '提示', '本次同步人员数:%d ' % countP, QMessageBox.Yes) else: runStatus = False progress.close() QMessageBox.information(self, '提示', '同步失败,原因:%s ' % self.cdzj.msg, QMessageBox.Yes) # self.cdzj.feedback('smz-a03', 3, '下发失败') break i += 1 else: progress.setValue(countD) QMessageBox.information(self, "提示", "操作成功") else: progress.deleteLater() QMessageBox.information(self, '提示', '未找到考勤设备!', QMessageBox.Yes) break
def autorotate(self): _rotate = lambda data, d, order=3: scipy.ndimage.interpolation.rotate(data, d, reshape=True, order=order, mode='constant', cval = self.background) def get_angle(data, min, max, xtol=1e-10): start = time.time() get_data = lambda d: self.__fwhm(_rotate(data, d), ypos=0.25)[0] result = minimize_scalar(get_data, bracket=[min,max], method='brent', options={'xtol': xtol}) print(result) print("elapsed: {}".format(time.time() - start)) return result.x progress = QProgressDialog("Calculating best rotation angle", None, 0, 4, self); progress.setWindowModality(Qt.WindowModal); progress.show() def show_progress(progressbar, progress, angle): progressbar.setValue(progress) QApplication.instance().processEvents() print("Step {}: {}".format(progress, round(angle, 5))) show_progress(progress, 0, 0) ratio = max(self.data.shape[0]/100, self.data.shape[1]/100) data = self.fits_file[self.image_hdu_index].data small = scipy.ndimage.interpolation.zoom(data, 1./ratio) angle = get_angle(small, 0, 180) show_progress(progress, 1, angle) #angle = get_angle(small, np.arange(angle-4., angle+4., step=0.01)) #show_progress(progress, 2, angle) angle = get_angle(scipy.ndimage.interpolation.zoom(data, 2./ratio) if 2./ratio < 1 else data, angle-2, angle+2) show_progress(progress, 2, angle) angle = get_angle(scipy.ndimage.interpolation.zoom(data, 3/ratio) if 3/ratio < 1 else data, angle-1, angle+1) show_progress(progress, 3, angle) angle = get_angle(self.data, angle-0.0002, angle+0.0002) show_progress(progress, 4, angle) angle = round(angle, 5) while angle < 0: angle += 360. while angle > 360: angle -= 360. progress.deleteLater() print("Step 5: {}".format(angle)) self.rotate(angle)
def progress_dialog(main_window: QMainWindow, title: str, label: str, maximum: int) -> ContextManager[QProgressDialog]: """:class:`~contextlib.contextmanager` that displays a progress dialog :param main_window: Application main window :param title: Progress dialog title :param label: Progress dialog label :param maximum: Maximum value for progress """ progress_dialog = QProgressDialog(main_window) progress_dialog.setWindowTitle(title) progress_dialog.setWindowModality(Qt.WindowModal) progress_dialog.setLabelText(label) progress_dialog.setMaximum(maximum) yield progress_dialog progress_dialog.setValue(maximum) progress_dialog.close() progress_dialog.deleteLater()
def process(self, mode): files = self.getFileList() dest_files = [] self.gui_config.converterConfig = ConverterConfig(self.config_file) self.gui_config.converterConfig.log = self.log if self.gui_config.embedFontFamily: self.generateFontCSS() config = self.gui_config.converterConfig if len(files) > 0: progressDlg = QProgressDialog(self) progressDlg.setWindowModality(Qt.WindowModal) progressDlg.setMinimumDuration(0) progressDlg.setLabelText(_translate('fb2mobi-gui', 'Converting...')) progressDlg.setRange(1, len(files)) progressDlg.setAutoClose(False) progressDlg.forceShow() # Подготовка профиля конвертера config.setCurrentProfile(self.gui_config.currentProfile) config.output_format = self.gui_config.currentFormat # Отключим отправку книг на Kinlde из командной строки config.send_to_kindle['send'] = False if self.gui_config.embedFontFamily: css_file = os.path.join( os.path.dirname(self.gui_config.config_file), 'profiles', '_font.css') if os.path.exists(css_file): config.current_profile['css'] = css_file if mode == PROCESS_MODE_CONVERT: config.output_dir = self.gui_config.outputFolder if self.gui_config.outputFolder else self.gui_config.lastUsedTargetPath else: config.output_dir = tempfile.mkdtemp() if self.gui_config.hyphens.lower() == 'yes': config.current_profile['hyphens'] = True elif self.gui_config.hyphens.lower() == 'no': config.current_profile['hyphens'] = False i = 1 errors = 0 for file in files: result = True progressDlg.setValue(i) output_dir = os.path.abspath(config.output_dir) file_name = os.path.join( output_dir, os.path.splitext(os.path.split(file)[1])[0]) if os.path.splitext(file_name)[1].lower() == '.fb2': file_name = os.path.splitext(file_name)[0] dest_file = '{0}.{1}'.format(file_name, config.output_format) # Перед конвертацией удалим старый файл if os.path.exists(dest_file): os.remove(dest_file) config.log.info(' ') fb2mobi.process_file(config, file, None) # Отметим результат конвертации item = None for j in range(self.rootFileList.childCount()): if file == self.rootFileList.child(j).text(2): item = self.rootFileList.child(j) if os.path.exists(dest_file): dest_files.append(dest_file) item.setIcon(0, self.iconGreen) else: item.setIcon(0, self.iconRed) errors += 1 if progressDlg.wasCanceled(): break i += 1 if errors > 0: QMessageBox.warning( self, _translate('fb2mobi-gui', 'Error'), _translate( 'fb2mobi-gui', 'Error while sending file(s). Check log for details.')) if mode == PROCESS_MODE_KINDLE: kindle_doc_path = os.path.join(self.kindle_path, 'documents') if self.gui_config.kindleDocsSubfolder: kindle_doc_path = os.path.join( kindle_doc_path, self.gui_config.kindleDocsSubfolder) if not os.path.isdir(kindle_doc_path): try: os.makedirs(kindle_doc_path) except: self.log.critical( 'Error while creating subfolder {0} in documents folder.' .format(self.gui_config.kindleDocsSubfolder)) self.log.debug('Getting details', exc_info=True) QMessageBox.critical( self, _translate('fb2mobi-gui', 'Error'), _translate('fb2mobi-gui'), 'Error while sending file(s). Check log for details.' ) return thumbnail_path = os.path.join(self.kindle_path, 'system', 'thumbnails') if not os.path.isdir(thumbnail_path): thumbnail_path = '' if os.path.exists(kindle_doc_path): progressDlg.setLabelText( _translate('fb2mobi-gui', 'Sending to Kindle...')) progressDlg.setRange(1, len(dest_files)) i = 1 errors = 0 for file in dest_files: progressDlg.setValue(i) try: shutil.copy2(file, kindle_doc_path) src_sdr_dir = '{0}.{1}'.format( os.path.splitext(file)[0], 'sdr') dest_sdr_dir = os.path.join( kindle_doc_path, os.path.split(src_sdr_dir)[1]) if os.path.isdir(src_sdr_dir): if os.path.isdir(dest_sdr_dir): shutil.rmtree(dest_sdr_dir) shutil.copytree(src_sdr_dir, dest_sdr_dir) # Создадим миниатюру обложки, если оперделили путь и установлен признак if thumbnail_path and self.gui_config.kindleSyncCovers: dest_file = os.path.join( kindle_doc_path, os.path.split(file)[1]) if os.path.exists(dest_file): synccovers.process_file( dest_file, thumbnail_path, 330, 470, False, False) except: self.log.critical( 'Error while sending file {0}.'.format(file)) self.log.debug('Getting details', exc_info=True) errors += 1 i += 1 if progressDlg.wasCanceled() or errors == 3: break if errors > 0: QMessageBox.critical( self, _translate('fb2mobi-gui', 'Error'), _translate( 'fb2mobi-gui', 'Error while sending file(s). Check log for details.' )) fb2mobi.rm_tmp_files(config.output_dir, True) if mode == PROCESS_MODE_MAIL: progressDlg.setLabelText( _translate('fb2mobi-gui', 'Sending via Gmail...')) progressDlg.setRange(1, len(dest_files)) kindle = SendToKindle() kindle.smtp_server = 'smtp.gmail.com' kindle.smtp_port = '587' kindle.smtp_login = self.gui_config.GoogleMail kindle.smtp_password = self.gui_config.GooglePassword kindle.user_email = self.gui_config.GoogleMail kindle.kindle_email = self.gui_config.KindleMail kindle.convert = False i = 1 errors = 0 for file in dest_files: progressDlg.setValue(i) try: kindle.send_mail([file]) except: self.log.critical( 'Error while sending file {0}.'.format(file)) self.log.debug('Getting details', exc_info=True) errors += 1 i += 1 if progressDlg.wasCanceled() or errors == 3: break if errors > 0: QMessageBox.critical( self, _translate('fb2mobi-gui', 'Error'), _translate( 'fb2mobi-gui', 'Error while sending file(s). Check log for details.' )) fb2mobi.rm_tmp_files(config.output_dir, True) progressDlg.deleteLater()
def autorotate(self): _rotate = lambda data, d, order=3: scipy.ndimage.interpolation.rotate( data, d, reshape=True, order=order, mode='constant', cval=self.background) def get_angle(data, min, max, xtol=1e-10): start = time.time() get_data = lambda d: self.__fwhm(_rotate(data, d), ypos=0.25)[0] result = minimize_scalar(get_data, bracket=[min, max], method='brent', options={'xtol': xtol}) print(result) print("elapsed: {}".format(time.time() - start)) return result.x progress = QProgressDialog("Calculating best rotation angle", None, 0, 4, self) progress.setWindowModality(Qt.WindowModal) progress.show() def show_progress(progressbar, progress, angle): progressbar.setValue(progress) QApplication.instance().processEvents() print("Step {}: {}".format(progress, round(angle, 5))) show_progress(progress, 0, 0) ratio = max(self.data.shape[0] / 100, self.data.shape[1] / 100) data = self.fits_file[self.image_hdu_index].data small = scipy.ndimage.interpolation.zoom(data, 1. / ratio) angle = get_angle(small, 0, 180) show_progress(progress, 1, angle) #angle = get_angle(small, np.arange(angle-4., angle+4., step=0.01)) #show_progress(progress, 2, angle) angle = get_angle( scipy.ndimage.interpolation.zoom(data, 2. / ratio) if 2. / ratio < 1 else data, angle - 2, angle + 2) show_progress(progress, 2, angle) angle = get_angle( scipy.ndimage.interpolation.zoom(data, 3 / ratio) if 3 / ratio < 1 else data, angle - 1, angle + 1) show_progress(progress, 3, angle) angle = get_angle(self.data, angle - 0.0002, angle + 0.0002) show_progress(progress, 4, angle) angle = round(angle, 5) while angle < 0: angle += 360. while angle > 360: angle -= 360. progress.deleteLater() print("Step 5: {}".format(angle)) self.rotate(angle)
def selectRP1210(self, automatic=False): logger.debug("Select RP1210 function called.") selection = SelectRP1210("CSU_RP1210") logger.debug(selection.dll_name) if not automatic: selection.show_dialog() elif not selection.dll_name: selection.show_dialog() dll_name = selection.dll_name protocol = selection.protocol deviceID = selection.deviceID speed = selection.speed if dll_name is None: #this is what happens when you hit cancel return #Close things down try: self.close_clients() except AttributeError: pass try: for thread in self.read_message_threads: thread.runSignal = False except AttributeError: pass progress = QProgressDialog(self) progress.setMinimumWidth(600) progress.setWindowTitle("Setting Up RP1210 Clients") progress.setMinimumDuration(3000) progress.setWindowModality(Qt.WindowModal) progress.setMaximum(6) # Once an RP1210 DLL is selected, we can connect to it using the RP1210 helper file. self.RP1210 = RP1210Class(dll_name) if self.RP1210_toolbar is None: self.setup_RP1210_menus() # We want to connect to multiple clients with different protocols. self.client_ids={} self.client_ids["CAN"] = self.RP1210.get_client_id("CAN", deviceID, "{}".format(speed)) progress.setValue(1) self.client_ids["J1708"] = self.RP1210.get_client_id("J1708", deviceID, "Auto") progress.setValue(2) self.client_ids["J1939"] = self.RP1210.get_client_id("J1939", deviceID, "{}".format(speed)) progress.setValue(3) #self.client_ids["ISO15765"] = self.RP1210.get_client_id("ISO15765", deviceID, "Auto") #progress.setValue(3) logger.debug('Client IDs: {}'.format(self.client_ids)) # If there is a successful connection, save it. file_contents={ "dll_name":dll_name, "protocol":protocol, "deviceID":deviceID, "speed":speed } with open(selection.connections_file,"w") as rp1210_file: json.dump(file_contents, rp1210_file) self.rx_queues={"Logger":queue.Queue(10000)} self.read_message_threads={} self.extra_queues = {"Logger":queue.Queue(10000)} self.isodriver = ISO15765Driver(self, self.extra_queues["Logger"]) # Set all filters to pass. This allows messages to be read. # Constants are defined in an included file i = 0 BUFFER_SIZE = 8192 logger.debug("BUFFER_SIZE = {}".format(BUFFER_SIZE)) for protocol, nClientID in self.client_ids.items(): QCoreApplication.processEvents() if nClientID is not None: # By turning on Echo Mode, our logger process can record sent messages as well as received. fpchClientCommand = (c_char*8192)() fpchClientCommand[0] = 1 #Echo mode on return_value = self.RP1210.SendCommand(c_short(RP1210_Echo_Transmitted_Messages), c_short(nClientID), byref(fpchClientCommand), 1) logger.debug('RP1210_Echo_Transmitted_Messages returns {:d}: {}'.format(return_value,self.RP1210.get_error_code(return_value))) #Set all filters to pas return_value = self.RP1210.SendCommand(c_short(RP1210_Set_All_Filters_States_to_Pass), c_short(nClientID), None, 0) if return_value == 0: logger.debug("RP1210_Set_All_Filters_States_to_Pass for {} is successful.".format(protocol)) #setup a Receive queue. This keeps the GUI responsive and enables messages to be received. self.rx_queues[protocol] = queue.Queue(10000) self.tx_queues[protocol] = queue.Queue(10000) self.extra_queues[protocol] = queue.Queue(10000) self.read_message_threads[protocol] = RP1210ReadMessageThread(self, self.rx_queues[protocol], self.extra_queues[protocol], self.RP1210.ReadMessage, nClientID, protocol,"CSU_RP1210") self.read_message_threads[protocol].setDaemon(True) #needed to close the thread when the application closes. self.read_message_threads[protocol].start() logger.debug("Started RP1210ReadMessage Thread.") self.statusBar().showMessage("{} connected using {}".format(protocol,dll_name)) if protocol == "J1939": self.isodriver = ISO15765Driver(self, self.extra_queues["J1939"]) else : logger.debug('RP1210_Set_All_Filters_States_to_Pass returns {:d}: {}'.format(return_value,self.RP1210.get_error_code(return_value))) if protocol == "J1939": fpchClientCommand[0] = 0x00 #0 = as fast as possible milliseconds fpchClientCommand[1] = 0x00 fpchClientCommand[2] = 0x00 fpchClientCommand[3] = 0x00 return_value = self.RP1210.SendCommand(c_short(RP1210_Set_J1939_Interpacket_Time), c_short(nClientID), byref(fpchClientCommand), 4) logger.debug('RP1210_Set_J1939_Interpacket_Time returns {:d}: {}'.format(return_value,self.RP1210.get_error_code(return_value))) else: logger.debug("{} Client not connected for All Filters to pass. No Queue will be set up.".format(protocol)) i+=1 progress.setValue(3+i) if self.client_ids["J1939"] is None or self.client_ids["J1708"] is None: QMessageBox.information(self,"RP1210 Client Not Connected.","The default RP1210 Device was not found or is unplugged. Please reconnect your Vehicle Diagnostic Adapter (VDA) and select the RP1210 device to use.") progress.deleteLater()
def open_open_logger2(self): filters = "{} Data Files (*.bin);;All Files (*.*)".format(self.title) selected_filter = "CAN Logger 2 Data Files (*.bin)" fname,_ = QFileDialog.getOpenFileName(self, 'Open CAN Logger 2 File', self.export_path, filters, selected_filter) if fname: file_size = os.path.getsize(fname) bytes_processed = 0 #update the data package progress = QProgressDialog(self) progress.setMinimumWidth(600) progress.setWindowTitle("Processing CAN Logger 2 Data File") progress.setMinimumDuration(0) progress.setWindowModality(Qt.WindowModal) progress.setModal(False) #Will lead to instability when trying to click around. progress.setMaximum(file_size) progress_label = QLabel("Processed {:0.3f} of {:0.3f} Mbytes.".format(bytes_processed/1000000,file_size/1000000)) progress.setLabel(progress_label) logger.debug("Importing file {}".format(fname)) with open(fname,'rb') as f: while True: line = f.read(512) if len(line) < 512: logger.debug("Reached end of file {}".format(fname)) break #check integrity bytes_to_check = line[0:508] crc_value = struct.unpack('<L',line[508:512])[0] if binascii.crc32(bytes_to_check) != crc_value: logger.warning("CRC Failed") break #print('CRC Passed') #print(line) #print(" ".join(["{:02X}".format(c) for c in line])) prefix = line[0:4] RXCount0 = struct.unpack('<L',line[479:483])[0] RXCount1 = struct.unpack('<L',line[483:487])[0] RXCount2 = struct.unpack('<L',line[487:491])[0] # CAN Controller Receive Error Counters. Can0_REC = line[491] Can1_REC = line[492] Can2_REC = line[493] # CAN Controller Transmit Error Counters Can0_TEC = line[494] Can1_TEC = line[495] Can2_TEC = line[496] # A constant ASCII Text file to preserve the original filename (and take up space) block_filename = line[497:505] #micro seconds to write the previous 512 bytes to the SD card (only 3 bytes so mask off the MSB) buffer_write_time = struct.unpack('<L',line[505:509])[0] & 0x00FFFFFF for i in range(4,487,25): # parse data from records channel = line[i] timestamp = struct.unpack('<L',line[i+1:i+5])[0] system_micros = struct.unpack('<L',line[i+5:i+9])[0] can_id = struct.unpack('<L',line[i+9:i+13])[0] dlc = line[i+13] if dlc == 0xFF: break micros_per_second = struct.unpack('<L',line[i+13:i+17])[0] & 0x00FFFFFF timestamp += micros_per_second/1000000 data_bytes = line[i+17:i+25] data = struct.unpack('8B',data_bytes)[0] #create an RP1210 data structure sa = can_id & 0xFF priority = (can_id & 0x1C000000) >> 26 edp = (can_id & 0x02000000) >> 25 dp = (can_id & 0x01000000) >> 24 pf = (can_id & 0x00FF0000) >> 16 if pf >= 0xF0: ps = (can_id & 0x0000FF00) >> 8 da = 0xFF else: ps = 0 da = (can_id & 0x0000FF00) >> 8 ps = struct.pack('B', ps) pf = struct.pack('B', pf) pgn = ps + pf + struct.pack('B', edp + dp) rp1210_message = struct.pack('<L',system_micros) rp1210_message += b'\x00' rp1210_message += pgn rp1210_message += struct.pack('B', priority) rp1210_message += struct.pack('B', sa) rp1210_message += struct.pack('B', da) rp1210_message += data_bytes self.rx_queues["Logger"].put((timestamp, rp1210_message)) bytes_processed += 512 progress.setValue(bytes_processed) progress_label.setText("Processed {:0.3f} of {:0.3f} Mbytes.".format(bytes_processed/1000000,file_size/1000000)) if progress.wasCanceled(): break QCoreApplication.processEvents() progress.deleteLater()
class AddonManagerDialog(QDialog): _packages = None def __init__(self, parent=None, **kwargs): super().__init__(parent, acceptDrops=True, **kwargs) self.setLayout(QVBoxLayout()) self.layout().setContentsMargins(0, 0, 0, 0) self.addonwidget = AddonManagerWidget() self.layout().addWidget(self.addonwidget) info_bar = QWidget() info_layout = QHBoxLayout() info_bar.setLayout(info_layout) self.layout().addWidget(info_bar) container = QWidget() container.setLayout(QHBoxLayout()) buttons = QDialogButtonBox( orientation=Qt.Horizontal, standardButtons=QDialogButtonBox.Ok | QDialogButtonBox.Cancel, ) empty = QWidget() empty.setFixedWidth(1) container.layout().addWidget(buttons) container.layout().addWidget(empty) addmore = QPushButton( "Add more...", toolTip="Add an add-on not listed below", autoDefault=False ) self.addonwidget.tophlayout.addWidget(addmore) addmore.clicked.connect(self.__run_add_package_dialog) buttons.accepted.connect(self.__accepted) buttons.rejected.connect(self.reject) empty = QWidget() empty.setFixedHeight(1) self.layout().addWidget(container) self.layout().addWidget(empty) self._executor = concurrent.futures.ThreadPoolExecutor(max_workers=1) if AddonManagerDialog._packages is None: self._f_pypi_addons = self._executor.submit(list_available_versions) else: self._f_pypi_addons = concurrent.futures.Future() self._f_pypi_addons.set_result(AddonManagerDialog._packages) self._f_pypi_addons.add_done_callback( method_queued(self._set_packages, (object,)) ) self.__progress = None # type: Optional[QProgressDialog] self.__thread = None self.__installer = None if not self._f_pypi_addons.done(): self.__progressDialog() def __run_add_package_dialog(self): dlg = QDialog(self, windowTitle="Add add-on by name") dlg.setAttribute(Qt.WA_DeleteOnClose) vlayout = QVBoxLayout() form = QFormLayout() form.setContentsMargins(0, 0, 0, 0) nameentry = QLineEdit( placeholderText="Package name", toolTip="Enter a package name as displayed on " "PyPI (capitalization is not important)") nameentry.setMinimumWidth(250) form.addRow("Name:", nameentry) vlayout.addLayout(form) buttons = QDialogButtonBox( standardButtons=QDialogButtonBox.Ok | QDialogButtonBox.Cancel ) okb = buttons.button(QDialogButtonBox.Ok) okb.setEnabled(False) okb.setText("Add") def changed(name): okb.setEnabled(bool(name)) nameentry.textChanged.connect(changed) vlayout.addWidget(buttons) vlayout.setSizeConstraint(QVBoxLayout.SetFixedSize) dlg.setLayout(vlayout) f = None def query(): nonlocal f name = nameentry.text() f = self._executor.submit(pypi_json_query_project_meta, [name]) okb.setDisabled(True) def ondone(f): error_text = "" error_details = "" try: pkgs = f.result() except Exception: log.error("Query error:", exc_info=True) error_text = "Failed to query package index" error_details = traceback.format_exc() pkg = None else: pkg = pkgs[0] if pkg is None: error_text = "'{}' not was not found".format(name) if pkg: method_queued(self.add_package, (object,))(pkg) method_queued(dlg.accept, ())() else: method_queued(self.__show_error_for_query, (str, str)) \ (error_text, error_details) method_queued(dlg.reject, ())() f.add_done_callback(ondone) buttons.accepted.connect(query) buttons.rejected.connect(dlg.reject) dlg.exec_() @Slot(str, str) def __show_error_for_query(self, text, error_details): message_error(text, title="Error", details=error_details) @Slot(object) def add_package(self, installable): # type: (Installable) -> None if installable.name in {p.name for p in self._packages}: return else: packages = self._packages + [installable] self.set_packages(packages) def __progressDialog(self): if self.__progress is None: self.__progress = QProgressDialog( self, minimum=0, maximum=0, labelText=self.tr("Retrieving package list"), sizeGripEnabled=False, windowTitle="Progress", ) self.__progress.setWindowModality(Qt.WindowModal) self.__progress.canceled.connect(self.reject) self.__progress.hide() return self.__progress @Slot(object) def _set_packages(self, f): if self.__progress is not None: self.__progress.hide() self.__progress.deleteLater() self.__progress = None try: packages = f.result() except Exception as err: message_warning( "Could not retrieve package list", title="Error", informative_text=str(err), parent=self ) log.error(str(err), exc_info=True) packages = [] else: AddonManagerDialog._packages = packages self.set_packages(packages) @Slot(object) def set_packages(self, installable): # type: (List[Installable]) -> None self._packages = packages = installable # type: List[Installable] installed = list_installed_addons() dists = {dist.project_name: dist for dist in installed} packages = {pkg.name: pkg for pkg in packages} # For every pypi available distribution not listed by # list_installed_addons, check if it is actually already # installed. ws = pkg_resources.WorkingSet() for pkg_name in set(packages.keys()).difference(set(dists.keys())): try: d = ws.find(pkg_resources.Requirement.parse(pkg_name)) except pkg_resources.VersionConflict: pass except ValueError: # Requirements.parse error ? pass else: if d is not None: dists[d.project_name] = d project_names = unique( itertools.chain(packages.keys(), dists.keys()) ) items = [] for name in project_names: if name in dists and name in packages: item = Installed(packages[name], dists[name]) elif name in dists: item = Installed(None, dists[name]) elif name in packages: item = Available(packages[name]) else: assert False items.append(item) self.addonwidget.set_items(items) def showEvent(self, event): super().showEvent(event) if not self._f_pypi_addons.done() and self.__progress is not None: QTimer.singleShot(0, self.__progress.show) def done(self, retcode): super().done(retcode) self._f_pypi_addons.cancel() self._executor.shutdown(wait=False) if self.__thread is not None: self.__thread.quit() self.__thread.wait(1000) def closeEvent(self, event): super().closeEvent(event) if self.__progress is not None: self.__progress.hide() self._f_pypi_addons.cancel() self._executor.shutdown(wait=False) if self.__thread is not None: self.__thread.quit() self.__thread.wait(1000) ADDON_EXTENSIONS = ('.zip', '.whl', '.tar.gz') def dragEnterEvent(self, event): urls = event.mimeData().urls() if any((OSX_NSURL_toLocalFile(url) or url.toLocalFile()) .endswith(self.ADDON_EXTENSIONS) for url in urls): event.acceptProposedAction() def dropEvent(self, event): """Allow dropping add-ons (zip or wheel archives) on this dialog to install them""" packages = [] names = [] for url in event.mimeData().urls(): path = OSX_NSURL_toLocalFile(url) or url.toLocalFile() if path.endswith(self.ADDON_EXTENSIONS): name, vers, summary, descr = (get_meta_from_archive(path) or (os.path.basename(path), '', '', '')) names.append(cleanup(name)) packages.append( Installable(name, vers, summary, descr or summary, path, [path])) future = concurrent.futures.Future() future.set_result((AddonManagerDialog._packages or []) + packages) self._set_packages(future) self.addonwidget.set_install_projects(names) def __accepted(self): steps = self.addonwidget.item_state() if steps: # Move all uninstall steps to the front steps = sorted( steps, key=lambda step: 0 if step[0] == Uninstall else 1 ) self.__installer = Installer(steps=steps) self.__thread = QThread(self) self.__thread.start() self.__installer.moveToThread(self.__thread) self.__installer.finished.connect(self.__on_installer_finished) self.__installer.error.connect(self.__on_installer_error) progress = self.__progressDialog() self.__installer.installStatusChanged.connect(progress.setLabelText) progress.show() progress.setLabelText("Installing") self.__installer.start() else: self.accept() def __on_installer_error(self, command, pkg, retcode, output): message_error( "An error occurred while running a subprocess", title="Error", informative_text="{} exited with non zero status.".format(command), details="".join(output), parent=self ) self.reject() def __on_installer_finished(self): message = "Please restart OASYS for changes to take effect." message_information(message, parent=self) self.accept()
class GUIWindow(QMainWindow): def __init__(self, app, pipeline=Pipeline()): super().__init__() self._app = app self._logger = logging.getLogger(self.__class__.__name__) self._is_initialized = False self.init_basic(pipeline) self.init_ui() self.init_controls() self.setWindowTitle("Cognigraph") self.setWindowIcon(QIcon(':/cognigraph_icon.png')) def init_basic(self, pipeline): self._pipeline = pipeline # type: Pipeline self._updater = AsyncUpdater(self._app, pipeline) self._pipeline._signal_sender.long_operation_started.connect( self._show_progress_dialog) self._pipeline._signal_sender.long_operation_finished.connect( self._hide_progress_dialog) self._pipeline._signal_sender.request_message.connect( self._show_message) self._pipeline._signal_sender.node_widget_added.connect( self._on_node_widget_added) self._controls = Controls(pipeline=self._pipeline) self._controls.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) self._controls.tree_widget.node_removed.connect(self._on_node_removed) if hasattr(self, "central_widget"): for w in self.central_widget.subWindowList(): self.central_widget.removeSubWindow(w) def init_controls(self): self.controls_dock.setWidget(self._controls) self.run_toggle_action.triggered.disconnect() self.run_toggle_action.triggered.connect(self._updater.toggle) self._updater._sender.run_toggled.connect(self._on_run_button_toggled) self._updater._sender.errored.connect(self._show_message) self.is_initialized = False def init_ui(self): self.central_widget = QMdiArea() self.setCentralWidget(self.central_widget) # -------- controls widget -------- # self.controls_dock = QDockWidget("Processing pipeline setup", self) self.controls_dock.setObjectName("Controls") self.controls_dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.controls_dock.visibilityChanged.connect( self._update_pipeline_tree_widget_action_text) self.addDockWidget(Qt.LeftDockWidgetArea, self.controls_dock) # self._controls.setMinimumWidth(800) # --------------------------------- # file_menu = self.menuBar().addMenu("&File") # file menu load_pipeline_action = self._createAction("&Load pipeline", self._load_pipeline) save_pipeline_action = self._createAction("&Save pipeline", self._save_pipeline) file_menu.addAction(load_pipeline_action) file_menu.addAction(save_pipeline_action) # -------- view menu & toolbar -------- # tile_windows_action = self._createAction( "&Tile windows", self.central_widget.tileSubWindows) view_menu = self.menuBar().addMenu("&View") view_menu.addAction(tile_windows_action) view_toolbar = self.addToolBar("View") view_toolbar.addAction(tile_windows_action) # ------------------------------------- # edit_menu = self.menuBar().addMenu("&Edit") self._toggle_pipeline_tree_widget_action = self._createAction( "&Hide pipeline settings", self._toggle_pipeline_tree_widget) edit_menu.addAction(self._toggle_pipeline_tree_widget_action) edit_toolbar = self.addToolBar("Edit") edit_toolbar.setObjectName("edit_toolbar") edit_toolbar.addAction(self._toggle_pipeline_tree_widget_action) # -------- run menu & toolbar -------- # self.run_toggle_action = self._createAction( "&Start", self._on_run_button_toggled) run_menu = self.menuBar().addMenu("&Run") self.initialize_pipeline = self._createAction("&Initialize pipeline", self.initialize) run_menu.addAction(self.run_toggle_action) run_menu.addAction(self.initialize_pipeline) run_toolbar = self.addToolBar("Run") run_toolbar.setObjectName("run_toolbar") run_toolbar.addAction(self.run_toggle_action) run_toolbar.addAction(self.initialize_pipeline) # ------------------------------------ # def _toggle_pipeline_tree_widget(self): if self.controls_dock.isHidden(): self.controls_dock.show() else: self.controls_dock.hide() def _update_pipeline_tree_widget_action_text(self, is_visible): if is_visible: self._toggle_pipeline_tree_widget_action.setText( "&Hide pipelne settings") else: self._toggle_pipeline_tree_widget_action.setText( "&Show pipelne settings") def _load_pipeline(self): file_dialog = QFileDialog(caption="Select pipeline file", directory=PIPELINES_DIR) ext_filter = "JSON file (*.json);; All files (*.*)" pipeline_path = file_dialog.getOpenFileName(filter=ext_filter)[0] if pipeline_path: self._logger.info("Loading pipeline configuration from %s" % pipeline_path) if not self._updater.is_paused: self.run_toggle_action.trigger() with open(pipeline_path, "r") as db: try: params_dict = json.load(db) except json.decoder.JSONDecodeError as e: self._show_message("Bad pipeline configuration file", detailed_text=str(e)) pipeline = self.assemble_pipeline(params_dict, "Pipeline") self.init_basic(pipeline) self.init_controls() # self.resize(self.sizeHint()) else: return def _save_pipeline(self): self._logger.info("Saving pipeline") file_dialog = QFileDialog(caption="Select pipeline file", directory=PIPELINES_DIR) ext_filter = "JSON file (*.json);; All files (*.*)" pipeline_path = file_dialog.getSaveFileName(filter=ext_filter)[0] if pipeline_path: self._logger.info("Saving pipeline configuration to %s" % pipeline_path) try: self._pipeline.save_pipeline(pipeline_path) except Exception as exc: self._show_message( "Cant`t save pipeline configuration to %s" % pipeline_path, detailed_text=str(exc), ) self._logger.exception(exc) def assemble_pipeline(self, d, class_name): node_class = getattr(nodes, class_name) node = node_class(**d["init_args"]) for child_class_name in d["children"]: child = self.assemble_pipeline(d["children"][child_class_name], child_class_name) node.add_child(child) return node def initialize(self): is_paused = self._updater.is_paused if not is_paused: self._updater.stop() self._logger.info("Initializing all nodes") async_initer = AsyncPipelineInitializer(pipeline=self._pipeline, parent=self) async_initer.no_blocking_execution() for node in self._pipeline.all_nodes: if hasattr(node, "widget"): if not node.widget.parent(): # widget not added to QMdiArea self._add_subwindow(node.widget, repr(node)) self.central_widget.tileSubWindows() self.run_toggle_action.setDisabled(False) if not is_paused: self._updater.start() def _finish_initialization(self): self.progress_dialog.hide() self.progress_dialog.deleteLater() for node in self._pipeline.all_nodes: if hasattr(node, "widget"): self._add_subwindow(node.widget, repr(node)) self.central_widget.tileSubWindows() def _add_subwindow(self, widget, title): sw = _HookedSubWindow(self.central_widget) sw.setWidget(widget) sw.setWindowTitle(title) widget.show() def _show_progress_dialog(self, text): # -------- setup progress dialog -------- # self.progress_dialog = QProgressDialog(self) self.progress_dialog.setLabelText(text) self.progress_dialog.setCancelButtonText(None) self.progress_dialog.setRange(0, 0) self.progress_dialog.show() def _hide_progress_dialog(self): self.progress_dialog.hide() self.progress_dialog.deleteLater() def _on_subwindow_close(self, close_event): pass def _on_node_widget_added(self, widget, widget_name): self._add_subwindow(widget, widget_name) self.central_widget.tileSubWindows() def _on_node_removed(self, tree_item): if hasattr(tree_item.node, "widget"): try: self.central_widget.removeSubWindow( tree_item.node.widget.parent()) except AttributeError: pass except Exception as exc: self._show_message( "Can`t remove widget for %s" % tree_item.node, detailed_text=str(exc), ) self._logger.exception(exc) def _show_message(self, text, detailed_text=None, level="error"): if level == "error": icon = QMessageBox.Critical elif level == "warning": icon = QMessageBox.Warning elif level == "info": icon = QMessageBox.Information msg = QMessageBox(self) msg.setIcon(icon) msg.setText(text) msg.setDetailedText(detailed_text) msg.show() def _createAction( self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, ): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/%s.png" % icon)) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: action.triggered.connect(slot) if checkable: action.setCheckable(True) return action def moveEvent(self, event): return super(GUIWindow, self).moveEvent(event) def _on_run_button_toggled(self, is_paused=True): if is_paused: self.run_toggle_action.setText("Start") else: self.run_toggle_action.setText("Pause") @property def is_initialized(self): return self._is_initialized @is_initialized.setter def is_initialized(self, value): if value: self.run_toggle_action.setDisabled(False) else: self.run_toggle_action.setDisabled(True) self._is_initialized = value @property def _node_widgets(self) -> List[QWidget]: node_widgets = list() for node in self._pipeline.all_nodes: try: node_widgets.append(node.widget) except AttributeError: pass return node_widgets