예제 #1
0
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()
예제 #2
0
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)
예제 #3
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")