class TrainingWindow(Window): """Abstraction for training view based on Window class""" def __init__(self, window_path: str) -> None: super().__init__(window_path) sys.stdout = EmittingStream( textWritten=self._add_info) # textWritten works this way self.lbl_cancel.mouseReleaseEvent = self._cancel_training # thread_pool and ml_worker setup. A training view needs 2 threads to work properly self._thread_pool = QThreadPool() self._thread_pool.setMaxThreadCount(2) self._ml_worker = LongWorker() self._ml_worker.set_params(self._train_model) self._ml_worker.signals.program_finished.connect(self.next) self._ml_worker.signals.program_error.connect(self.handle_error) self._ml_worker.signals.result.connect(self._add_info) self._ml_worker.setAutoDelete(True) self._thread_pool.start(self._ml_worker, priority=1) def close_window(self) -> None: super(TrainingWindow, self).close_window() widget.close() def next(self) -> None: QThread.sleep(1) next_form = FinalResultWindow() widget.addWidget(next_form) widget.removeWidget(widget.currentWidget()) widget.setCurrentIndex(widget.currentIndex()) @abstractmethod def _train_model(self) -> None: pass def last_warning_pop_up(self) -> bool: pop_up: PopUp = WarningPopUp() title = "Cancelar entrenamiento" body = "¿Estas seguro que deseas cancelar el entrenamiento?" additional = "La aplicación se cerrará para evitar conflictos con las variables utilizadas hasta el momento." answer = pop_up.open_pop_up(title, body, additional) return answer def _cancel_training(self, event) -> None: """Show a Warning pop up and then if user wants to finished the app, close it""" event.accept() want_to_stop_training = self.last_warning_pop_up() if want_to_stop_training: self._thread_pool.cancel(self._ml_worker) self.close_window() def handle_error(self, error) -> None: """Print error message to the QTextEdit""" def write_error(): for i in info: self._add_info(i) QThread.sleep(1) # deactivate lbl press behaviour due to an error lbl_cancel_style = cancel_buttons_style["Not_available"] self.lbl_cancel.mouseReleaseEvent = None self.lbl_cancel.setStyleSheet(lbl_cancel_style) info = ("Error\n", str(error), "\nCerrando aplicación para evitar conflictos de memoria" + " ", ".", ".", ".") # worker to write info to ted_info temp_worker = LongWorker(func=write_error) temp_worker.signals.program_finished.connect(self.close_window) self._thread_pool.start(temp_worker, priority=2) def _add_info(self, info: str) -> None: """Append text to the QTextEdit.""" cursor = self.ted_info.textCursor() cursor.movePosition(QTextCursor.End) cursor.insertText(info) self.ted_info.setTextCursor(cursor) self.ted_info.ensureCursorVisible()
class DataProcess(DataGUI): # Main GUI for data module sdk_level_signal = QtCore.pyqtSignal(list) authority_signal = QtCore.pyqtSignal(list) type_signal = QtCore.pyqtSignal(list) add_apk_signal = pyqtSignal(int, int, int) add_progress_signal = pyqtSignal(float) market_signal = pyqtSignal(list) app_signal = pyqtSignal(list) update_signal = pyqtSignal(list) update_information_signal = pyqtSignal(list) delete_apk_signal = pyqtSignal() delete_progress_signal = pyqtSignal(float) error_signal = pyqtSignal(str) market_model = None app_model = None update_model = None search_app_thread = None search_platform_thread = None search_update_thread = None search_update_info_thread = None inbox_update_id_list = [] def __init__(self): super(DataProcess, self).__init__() self.thread_pool = QThreadPool() self.thread_pool.globalInstance() self.thread_pool.setMaxThreadCount(8) self.bind_error() self.load_data() self.bind_add_apk() self.bind_search() self.bind_delete() self.check_value() """ 加载ComboBox数据 """ def load_data(self): # sdk level combobox sdk_thread = SDKLevelThread() sdk_thread.transfer(self) self.sdk_level_signal.connect(self.update_sdk) self.thread_pool.start(sdk_thread) # authority combobox authority_thread = AuthorityThread() authority_thread.transfer(self) self.authority_signal.connect(self.update_authority) self.thread_pool.start(authority_thread) # type combobox type_thread = TypeThread() type_thread.transfer(self) self.type_signal.connect(self.update_type) self.thread_pool.start(type_thread) def update_sdk(self, sdk_list): sdk_list = ["UNKNOWN"] + sdk_list self.sdk_list = sdk_list self.sdk_combobox.addItems(sdk_list) def update_authority(self, authority_list): if not authority_list: return authority_index_list, authority_name_list = zip(*authority_list) authority_name_list = list(authority_name_list) self.authority_id_list = list(authority_index_list) self.authority_combobox.addItems(authority_name_list) def update_type(self, type_list): if not type_list: return type_index_list, type_name_list = zip(*type_list) self.type_id_list = list(type_index_list) self.type_combobox.addItems(type_name_list) """ 查找 """ def bind_search(self): self.search_button.clicked.connect(self.search_click) self.market_signal.connect(self.update_market) self.first_file_tree.setEditTriggers(QAbstractItemView.NoEditTriggers) self.first_file_tree.clicked.connect(self.first_tree_click) self.app_signal.connect(self.update_app) self.second_file_tree.setEditTriggers(QAbstractItemView.NoEditTriggers) self.second_file_tree.clicked.connect(self.second_tree_click) self.update_signal.connect(self.update_update) self.third_file_tree.setEditTriggers(QAbstractItemView.NoEditTriggers) self.third_file_tree.clicked.connect(self.third_tree_click) self.update_information_signal.connect(self.update_information) self.bind_drag_search() def search_click(self): # get the combobox value sdk_name_list = self.sdk_combobox.get_select_text() authority_select_list = self.authority_combobox.get_select_index() app_type_select_list = self.type_combobox.get_select_index() # 选中全部sdk 或 未选中任何sdk时,无需筛选 if len(sdk_name_list) == len(self.sdk_list) or len(sdk_name_list) == 0: sdk_name_list = None self.selected_sdk_name_list = sdk_name_list # 未选中任何authority时,无需筛选 if len(authority_select_list) == 0: authority_id_list = None else: authority_id_list = [ self.authority_id_list[_index_] for _index_ in authority_select_list ] self.selected_authority_id_list = authority_id_list # 未选中任何type 或 选中全部type时, 无需筛选 if len(app_type_select_list) == 0 or len(app_type_select_list) == len( self.type_id_list): type_id_list = None else: type_id_list = [ self.type_id_list[_index_] for _index_ in app_type_select_list ] self.selected_type_id_list = type_id_list search_platform_thread = SearchPlatformThread() search_platform_thread.transfer(self, sdk_name_list, authority_id_list, type_id_list) if self.search_platform_thread: # 取消上一个请求 try: self.thread_pool.cancel(self.search_platform_thread) except RuntimeError: pass self.search_platform_thread = search_platform_thread self.thread_pool.start(search_platform_thread) def update_market(self, market_list): platform_model = QStandardItemModel() icon_path = os.path.join(__current_folder_path__, "./images/folder.png") for market in market_list: platform_model.appendRow( QStandardItem(QIcon(icon_path), market['market_name'])) self.market_list = market_list if self.market_model: self.market_model.deleteLater() self.market_model = platform_model self.first_file_tree.setModel(platform_model) self.first_file_tree.scrollTo(platform_model.index(0, 0)) # clear the second tree app_model = QStandardItemModel() self.app_list = [] if self.app_model: self.app_model.deleteLater() self.app_model = app_model self.second_file_tree.setModel(app_model) # clear the third tree update_model = QStandardItemModel() self.update_list = [] if self.update_model: self.update_model.deleteLater() self.update_model = update_model self.third_file_tree.setModel(update_model) # clear the information box self.clear_apk_info_layout() self.inbox_update_id_list = [] # not find any data if len(market_list) == 0: QMessageBox().warning(self, "Not Found", "Not found any apk in database.", QMessageBox.Ok) def first_tree_click(self): current_row_index = self.first_file_tree.currentIndex().row() search_app_thread = SearchAppThread() search_app_thread.transfer( self, self.market_list[current_row_index]['market_id'], self.selected_sdk_name_list, self.selected_authority_id_list, self.selected_type_id_list) if self.search_app_thread: # 取消上一个请求 try: self.thread_pool.cancel(self.search_app_thread) except RuntimeError: pass self.search_app_thread = search_app_thread self.thread_pool.start(search_app_thread) def update_app(self, app_list): app_model = QStandardItemModel() icon_path = os.path.join(__current_folder_path__, "./images/android.png") for app in app_list: app_model.appendRow( QStandardItem(QIcon(icon_path), app['app_title'])) self.app_list = app_list if self.app_model: self.app_model.deleteLater() self.app_model = app_model self.second_file_tree.setModel(app_model) self.second_file_tree.scrollTo(app_model.index(0, 0)) def second_tree_click(self): current_row_index = self.second_file_tree.currentIndex().row() search_update_thread = SearchUpdateThread() search_update_thread.transfer( self, self.app_list[current_row_index]['app_id'], self.selected_sdk_name_list, self.selected_authority_id_list, self.selected_type_id_list) if self.search_update_thread: # 取消上一个请求 try: self.thread_pool.cancel(self.search_update_thread) except RuntimeError: pass self.search_update_thread = search_update_thread self.thread_pool.start(search_update_thread) def update_update(self, update_list): update_model = QStandardItemModel() icon_path = os.path.join(__current_folder_path__, "./images/version.png") for update in update_list: version = update['version'].split( '.apk')[0] if update['version'].endswith( '.apk') else update['version'] version = update['version'].split( '.xapk')[0] if update['version'].endswith('.xapk') else version update_model.appendRow(QStandardItem(QIcon(icon_path), version)) self.update_list = update_list if self.update_model: self.update_model.deleteLater() self.update_model = update_model self.third_file_tree.setModel(update_model) self.third_file_tree.scrollTo(update_model.index(0, 0)) def third_tree_click(self): current_third_tree_row_index = self.third_file_tree.currentIndex().row( ) search_apk_info_by_update_id_thread = SearchApkInfoByUpdateIdThread() search_apk_info_by_update_id_thread.transfer( self, self.update_list[current_third_tree_row_index]['update_id']) if self.search_update_info_thread: # 取消上一个请求 try: self.thread_pool.cancel(self.search_update_info_thread) except RuntimeError: pass self.search_update_info_thread = search_apk_info_by_update_id_thread self.thread_pool.start(search_apk_info_by_update_id_thread) # clear the information box self.clear_apk_info_layout() self.inbox_update_id_list = [] def update_information(self, information_list): self.clear_apk_info_layout() inbox_update_id_list = [] for information in information_list: # add the new information widget information['market'] = information['market_name'] update_folder = get_app_folder(information) image_file_list = glob.glob(os.path.join(update_folder, "*.jpg")) description_file = os.path.join(update_folder, "description.txt") if os.path.exists(description_file): with open(description_file, 'r') as _file_: description = _file_.read().strip() if description != "": information['description'] = description information['image_file_list'] = image_file_list new_information_widget = InformationWidget() new_information_widget.load_data(information) self.apk_info_layout.addWidget(new_information_widget) inbox_update_id_list.append(information['update_id']) self.inbox_update_id_list = inbox_update_id_list """ 拖动查找 """ def bind_drag_search(self): self.apk_info_scroll_area.file_signal.connect(self.drag_search) def drag_search(self, file_url): drag_search_thread = DragSearchThread() drag_search_thread.transfer(self, file_url) if self.search_app_thread: # 取消上一个进程 try: self.thread_pool.cancel(self.search_app_thread) except RuntimeError: pass self.search_app_thread = drag_search_thread self.thread_pool.start(drag_search_thread) # uncheck the third tree row_index = self.third_file_tree.currentIndex().row() if row_index != -1: self.third_file_tree.setCurrentIndex( self.update_model.index(-1, -1)) # clear the information box self.clear_apk_info_layout() self.inbox_update_id_list = [] """ 删除 """ def bind_delete(self): self.delete_apk_button.clicked.connect(self.delete_apk_button_click) self.delete_apk_signal.connect(self.delete_apk_success) self.delete_from_folder_button.clicked.connect( self.delete_from_folder_button_click) def delete_apk_button_click(self): if not self.inbox_update_id_list: return # clear the information box self.clear_apk_info_layout() inbox_update_id_list = self.inbox_update_id_list self.inbox_update_id_list = [] # check the third file system tree in_third_tree = False reserved_update_list = [] # type: List[Dict] for update in self.update_list: if update['update_id'] in inbox_update_id_list: in_third_tree = True else: reserved_update_list.append(update) if in_third_tree: new_update_model = QStandardItemModel() icon_path = os.path.join(__current_folder_path__, "./images/version.png") for update in reserved_update_list: version = update['version'].split( '.apk')[0] if update['version'].endswith( '.apk') else update['version'] version = update['version'].split( '.xapk')[0] if update['version'].endswith( '.xapk') else version new_update_model.appendRow( QStandardItem(QIcon(icon_path), version)) self.update_list = reserved_update_list if self.update_model: self.update_model.deleteLater() self.update_model = new_update_model self.third_file_tree.setModel(new_update_model) self.third_file_tree.scrollTo(new_update_model.index(0, 0)) # start the delete thread delete_apk_thread = DeleteApkThread() delete_apk_thread.transfer(self, inbox_update_id_list) self.thread_pool.start(delete_apk_thread) def delete_apk_success(self): QMessageBox.information(self, "Delete successfully", "Successfully delete APK(s).", QMessageBox.Yes) self.delete_from_folder_button.setVisible(True) self.delete_progress_bar.setValue(0) self.delete_progress_bar.setVisible(False) def delete_from_folder_button_click(self): dir_choose = QFileDialog.getExistingDirectory( self, "Choose APK Directory", os.path.join(__current_folder_path__, "../../")) if not dir_choose: return user_choose = QMessageBox.question( self, "Delete Confirm", "Do confirm to delete folder '{}'?.".format(dir_choose), QMessageBox.Yes | QMessageBox.Cancel, QMessageBox.Cancel) if user_choose == QMessageBox.Cancel: return # set the layout self.delete_from_folder_button.setVisible(False) self.delete_progress_bar.setValue(0) self.delete_progress_bar.setVisible(True) # start the delete thread delete_thread = MultiDeleteThread() delete_thread.transfer(self, dir_choose) self.thread_pool.start(delete_thread) """ 错误 """ def bind_error(self): self.error_signal.connect(self.catch_error) def catch_error(self, _err_: str): log_file = os.path.join( __current_folder_path__, "../../log/main_gui.{}.log".format( datetime.datetime.now().strftime("%Y-%m-%d-%H"))) with open(log_file, 'a') as _file_: _file_.write(_err_) def check_value(self): enviro = True if python_interface is None: QMessageBox.warning( self, "Python Interface Error", "Please set the 'python_interface' in setting.py.", QMessageBox.Ok, QMessageBox.Ok) enviro = False return enviro """ 批量添加APK """ def bind_add_apk(self): self.add_progress_signal.connect(self.add_apk_progress_bar.setValue) self.add_apk_signal.connect(self.add_apk_success) self.add_apk_button.clicked.connect(self.add_apk_button_click) def add_apk_button_click(self): dir_choose = QFileDialog.getExistingDirectory( self, "Choose APK Directory", os.path.join(__current_folder_path__, "../../")) if not dir_choose: return self.add_apk_button.setVisible(False) self.add_apk_progress_bar.setValue(0) self.add_apk_progress_bar.setVisible(True) add_apk_thread = AddAPKThread() add_apk_thread.transfer(self, dir_choose) self.thread_pool.start(add_apk_thread) def add_apk_success(self, success_number, repeated_number, error_number): QMessageBox.information( self, "Add APK", "Successfully add APKs. {} success, {} Repeated and {} error.". format(success_number, repeated_number, error_number), QMessageBox.Ok, QMessageBox.Ok) self.add_apk_button.setVisible(True) self.add_apk_progress_bar.setVisible(False) self.add_apk_progress_bar.setValue(0)
class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(600, 500) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) self.verticalLayout.setObjectName("verticalLayout") # images table self.tableWidget = table.ImageTableWidget(self.centralwidget) self.tableWidget.setObjectName("tableWidget") self.verticalLayout.addWidget(self.tableWidget) self.path_count = 0 self.extension_count = 0 self.status_count = 0 self.rowCount = 0 self.worker = None self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget) self.pushButton_2.setObjectName("pushButton_2") # select one image(file) self.pushButton = QtWidgets.QPushButton(self.centralwidget) self.pushButton.setObjectName("pushButton") self.horizontalLayout_2.addWidget(self.pushButton) self.verticalLayout.addLayout(self.horizontalLayout_2) self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_3") self.comboBox = QtWidgets.QComboBox(self.centralwidget) self.comboBox.setObjectName("comboBox") self.horizontalLayout_3.addWidget(self.comboBox) self.pushButton_save = QtWidgets.QPushButton(self.centralwidget) self.verticalLayout.addLayout(self.horizontalLayout_3) self.horizontalLayout_3.addWidget(self.pushButton_save) # cancel converting # self.pushButton_cancel_converting = QtWidgets.QPushButton(self.centralwidget) # self.horizontalLayout_3.addWidget(self.pushButton_cancel_converting) # select folder & subfolder checkbox self.horizontalLayout_folder_subfolder = QtWidgets.QHBoxLayout() self.checkBox = QtWidgets.QCheckBox(self.centralwidget) self.checkBoxLabel = QtWidgets.QLabel(self.centralwidget) self.checkBoxLabel.setText("sub folder") self.horizontalLayout_folder_subfolder.addWidget(self.pushButton_2) self.horizontalLayout_folder_subfolder.addWidget(self.checkBoxLabel) self.horizontalLayout_folder_subfolder.addWidget(self.checkBox) self.horizontalLayout_2.addLayout( self.horizontalLayout_folder_subfolder) # progressbar self.progressbar = QtWidgets.QProgressBar(self.centralwidget) self.verticalLayout.addWidget(self.progressbar) self.progressbar.setValue(0) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 449, 21)) self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile.setObjectName("menuFile") self.menuHelp = QtWidgets.QMenu(self.menubar) self.menuHelp.setObjectName("menuHelp") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.actionAbout = QtWidgets.QAction(MainWindow) self.actionAbout.setObjectName("actionAbout") self.actionOpen_image = QtWidgets.QAction(MainWindow) self.actionOpen_image.setObjectName("actionOpen_image") self.actionOpen_folder = QtWidgets.QAction(MainWindow) self.actionOpen_folder.setObjectName("actionOpen_folder") self.actionExit = QtWidgets.QAction(MainWindow) self.actionExit.setObjectName("actionExit") self.actionClearList = QtWidgets.QAction(MainWindow) self.menuFile.addAction(self.actionOpen_image) self.menuFile.addAction(self.actionOpen_folder) self.menuFile.addAction(self.actionClearList) self.menuFile.addAction(self.actionExit) self.menuHelp.addAction(self.actionAbout) self.menubar.addAction(self.menuFile.menuAction()) self.menubar.addAction(self.menuHelp.menuAction()) # threading part self.pool = QThreadPool() self.pool.setMaxThreadCount(5) self.connects() self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "Image-converter")) self.pushButton_2.setText(_translate("MainWindow", "select folder")) self.pushButton.setText(_translate("MainWindow", "select image")) self.pushButton_save.setText( _translate("MainWindow", "Convert && Save".encode(encoding="utf-8"))) self.pushButton_save.setDisabled(True) self.menuFile.setTitle(_translate("MainWindow", "File")) self.menuHelp.setTitle(_translate("MainWindow", "Help")) self.actionAbout.setText(_translate("MainWindow", "About")) self.actionOpen_image.setText(_translate("MainWindow", "Open image")) self.actionOpen_folder.setText(_translate("MainWindow", "Open folder")) self.actionExit.setText(_translate("MainWindow", "Exit")) self.actionClearList.setText(_translate("MainWindow", "Clear list")) self.comboBox.addItems(batch.extensions) #self.pushButton_cancel_converting.setText(_translate("MainWindow", "Cancel")) def connects(self): self.pushButton.clicked.connect(self.browse_single_image) self.actionAbout.triggered.connect(about.show_dialog) self.actionExit.triggered.connect(sys.exit) self.pushButton_save.clicked.connect(self.convert) self.pushButton_2.clicked.connect(self.browse_directory) self.actionClearList.triggered.connect(self.clearTableItems) self.actionOpen_folder.triggered.connect(self.browse_directory) self.actionOpen_image.triggered.connect(self.browse_single_image) #self.pushButton_cancel_converting.clicked.connect(self.cancel_converting) # @clear @table @clear.table def clearTableItems(self): self.progressbar.setValue(0) self.path_count = 0 self.extension_count = 0 self.status_count = 0 self.rowCount = 0 images.clear() self.tableWidget.setRowCount(0) def browse_single_image(self): filename = QtWidgets.QFileDialog.getOpenFileName( self.centralwidget, 'Open file', 'C:\\', "Image files (*.jpg *.gif *.tiff *.*png *.bmp *.ico *.pnm)") if (len(filename[0]) > 0): # if user selected a file self.rowCount += 1 self.tableWidget.setRowCount(self.rowCount) self.addItemToTable(filename[0], column="path") self.addItemToTable(filename[0].split(".")[-1], column="extension") images.append(filename[0]) self.pushButton_save.setEnabled(True) self.comboBox.setCurrentText(filename[0].split(".")[-1]) print(filename[0]) def addItemToTable(self, value, column=''): if (column == "path"): self.tableWidget.setItem(self.path_count, 0, QtWidgets.QTableWidgetItem(value)) self.path_count += 1 if (column == "extension"): self.tableWidget.setItem(self.extension_count, 1, QtWidgets.QTableWidgetItem(value)) self.extension_count += 1 if (column == "status"): self.tableWidget.setItem(self.status_count, 2, QtWidgets.QTableWidgetItem(value)) self.status_count += 1 def cancel_converting(self): self.pool.cancel(self.worker) def convert(self): output_dirname = QtWidgets.QFileDialog.getExistingDirectory( self.centralwidget) self.progressbar.setValue(0) # warning: hardcoded _progress = 1 self.progressbar.setMaximum(len(images)) self.progressbar.setMinimum(0) if output_dirname and images: for image in set(images): _progress += 1 self.progressbar.setValue(_progress) image_name = '' if image.count("/") > 0 and not image.count("\\") > 0: image_name = image.split(r".")[0].split("/")[-1] else: image_name = image.split(r".")[0].split("\\")[-1] final_outpath = output_dirname + os.sep + image_name single.single_convert(image, final_outpath, extension=self.comboBox.currentText()) # directory def browse_directory(self): directory = QtWidgets.QFileDialog.getExistingDirectory( self.centralwidget) if (len(directory) > 0): self.pushButton_save.setEnabled(True) # @checkbox @subfolder if self.checkBox.isChecked(): _images = utils.System.files_tree_list( directory, extensions=batch.extensions) if _images.__len__() > 0: images.extend(_images) for image in _images: self.rowCount += 1 self.tableWidget.setRowCount(self.rowCount) print(image) self.addItemToTable(image, column="path") self.addItemToTable(image.split(".")[-1], column="extension") else: _images = utils.System.files_list(directory, extensions=batch.extensions) if _images.__len__() > 0: images.extend(_images) for image in _images: self.rowCount += 1 self.tableWidget.setRowCount(self.rowCount) print(image) self.addItemToTable(image, column="path") self.addItemToTable(image.split(".")[-1], column="extension")