Пример #1
0
class Lg_addFiles(QDialog, Ui_addFile, object):
    closeGUI_signal = pyqtSignal()
    inputSig = pyqtSignal(list, list, bool, str)
    inputContentSig = pyqtSignal(str, str)
    exception_signal = pyqtSignal(str)
    progressDiologSig = pyqtSignal(int)
    fastaDownloadFinishedSig = pyqtSignal(str)
    inputFasSig = pyqtSignal(str, str)

    def __init__(self, exportPath=None, parent=None):
        super(Lg_addFiles, self).__init__(parent)
        self.factory = Factory()
        self.parent = parent
        self.thisPath = self.factory.thisPath
        self.exportPath = exportPath
        # 保存设置
        self.addFiles_settings = QSettings(
            self.thisPath +
            '/settings/addFiles_settings.ini',
            QSettings.IniFormat)
        self.closeGUI_signal.connect(self.close)
        self.progressDiologSig.connect(self.runProgressDialog)
        # self.close() 不能在信号槽里面
        self.fastaDownloadFinishedSig.connect(self.parent.setTreeViewFocus)
        # 开始装载样式表
        with open(self.thisPath + os.sep + 'style.qss', encoding="utf-8", errors='ignore') as f:
            self.qss_file = f.read()
        self.setStyleSheet(self.qss_file)
        self.setupUi(self)
        self.guiRestore()
        self.exception_signal.connect(self.popupException)
        self.interrupt = False
        self.label_3.clicked.connect(lambda : QDesktopServices.openUrl(QUrl(
            "https://dongzhang0725.github.io/dongzhang0725.github.io/documentation/#4-3-1-1-Brief-example")))

    def fetSeqFromNCBI(self, id_array):
        batch_size = 20
        count = len(id_array)
        download_contents = ""
        for start in range(0, count, batch_size):
            if self.interrupt:
                return
            end = min(count, start + batch_size)
            print("Going to download record %i to %i" % (start + 1, end))
            if (start + batch_size) > count:
                batch_size = count - start
            Entrez.email = self.email if self.email else "*****@*****.**"
            fetch_handle = Entrez.efetch(db="nucleotide", rettype=self.rettype, retmode="text",
                                         retstart=start, retmax=batch_size, id=id_array)
            download_contents += fetch_handle.read()
            self.progressDiologSig.emit(end * 100 / count)
        if self.rettype == "gb":
            self.inputContentSig.emit(
                download_contents, self.outputPath)
        else:
            with open(self.outputPath + os.sep + self.fasta_file_name, "w", encoding="utf-8") as f:
                f.write(download_contents)
            self.fastaDownloadFinishedSig.emit(self.outputPath)
        # result_handle = Entrez.efetch(
        #     db="nucleotide", rettype="gb",  id=id_array, retmode="text")
        # # with open(self.exportPath + os.sep + "new.gb", "w", encoding="utf-8") as f2:
        # #     f2.write(result_handle.read())
        # self.inputContentSig.emit(
        #     result_handle.read(), [])

    @pyqtSlot()
    def on_pushButton_clicked(self):
        self.outputPath = self.fetchOutputPath()
        if self.parent.isWorkFolder(self.outputPath, mode="gb"):
            files = QFileDialog.getOpenFileNames(
                self, "Input GenBank Files", filter="GenBank and Fasta Format (*.gb *.gbk *.gbf *.gp *.gbff *.fas *.fasta);;")
            if files[0]:
                list_gbs = []
                list_fas = []
                for i in files[0]:
                    if os.path.splitext(i)[1].upper() in [".GB", ".GBK", ".GP", ".GBF", ".GBFF"]:
                        list_gbs.append(i)
                    elif os.path.splitext(i)[1].upper() in [".FAS", ".FASTA"]:
                        list_fas.append(i)
                if list_gbs:
                    self.inputSig.emit(list_gbs, [], False, self.outputPath)
                if list_fas:
                    fasContent = ""
                    for i in list_fas:
                        with open(i, encoding="utf-8", errors='ignore') as f:
                            fasContent += f.read() + "\n"
                    self.inputFasSig.emit(fasContent, self.outputPath)
                self.close()
                self.deleteLater()
                del self
        else:
            files = QFileDialog.getOpenFileNames(
                self, "Input Files",
                filter="Supported Format (*.docx *.doc *.odt *.docm *.dotx *.dotm *.dot "
                       "*.fas *.fasta *.phy *.phylip *.nex *.nxs *.nexus);;")
            if files[0]:
                self.inputSig.emit([], files[0], False, self.outputPath)
                self.close()
                self.deleteLater()
                del self

    @pyqtSlot()
    def on_pushButton_2_clicked(self):
        # download
        self.interrupt = False
        text_content = self.plainTextEdit.toPlainText()
        if text_content:
            self.outputPath = self.fetchOutputPath()
            self.rettype = "gb" if self.parent.isWorkFolder(self.outputPath, mode="gb") else "fasta"
            if self.rettype == "fasta":
                name, ok = QInputDialog.getText(
                    self, 'Set output file name', 'Output file name:', text="sequence.fas")
                if ok:
                    self.fasta_file_name = name + ".fas" if "." not in name else name
                    if os.path.exists(self.outputPath + os.sep + self.fasta_file_name):
                        reply = QMessageBox.question(
                            self,
                            "Concatenate sequence",
                            "<p style='line-height:25px; height:25px'>The file exists, replace it?</p>",
                            QMessageBox.Yes,
                            QMessageBox.Cancel)
                        if reply == QMessageBox.Cancel:
                            return
                else:
                    QMessageBox.information(
                        self,
                        "Information",
                        "<p style='line-height:25px; height:25px'>Download canceled!</p>")
                    return
            self.downloadState("start")
            self.progressDialog = self.factory.myProgressDialog(
                "Please Wait", "Downloading...", parent=self)
            self.progressDialog.show()
            self.id_array = re.split(r"\s|,", text_content)
            while "" in self.id_array:
                self.id_array.remove("")
            self.email = self.lineEdit.text()
            self.worker_download = WorkThread(self.run_command, parent=self)
            self.progressDialog.canceled.connect(lambda: [setattr(self, "interrupt", True),
                                                          self.worker_download.stopWork(),
                                                          self.progressDialog.close(),
                                                          self.downloadState("stop")])
            self.worker_download.start()
        else:
            QMessageBox.information(
                self,
                "Information",
                "<p style='line-height:25px; height:25px'>Please input ID(s) first</p>")

    @pyqtSlot()
    def on_pushButton_8_clicked(self):
        #search in NCBI
        self.close()
        self.parent.on_SerhNCBI_triggered()

    @pyqtSlot()
    def on_toolButton_clicked(self):
        info = '''To make use of NCBI's E-utilities, NCBI requires you to specify your email address with each request.<br> 
In case of excessive usage of the E-utilities, NCBI will attempt to contact a user at the email address provided before blocking access to the E-utilities.'''
        QMessageBox.information(
            self,
            "Information",
            "<p style='line-height:25px; height:25px'>%s</p>"%info)

    def run_command(self):
        try:
            self.fetSeqFromNCBI(self.id_array)
            self.closeGUI_signal.emit()
        except BaseException:
            self.exceptionInfo = ''.join(
                traceback.format_exception(
                    *sys.exc_info()))  # 捕获报错内容,只能在这里捕获,没有报错的地方无法捕获
            self.exception_signal.emit(self.exceptionInfo)
            # self.popupException(self.exceptionInfo)  # 激发这个信号

    def popupException(self, exception):
        msg = QMessageBox(self)
        msg.setIcon(QMessageBox.Critical)
        msg.setText(
            'The program encountered an unforeseen problem, please report the bug at <a href="https://github.com/dongzhang0725/PhyloSuite/issues">https://github.com/dongzhang0725/PhyloSuite/issues</a> or send an email with the detailed traceback to [email protected]')
        msg.setWindowTitle("Error")
        msg.setDetailedText(exception)
        msg.setStandardButtons(QMessageBox.Ok)
        msg.exec_()
        self.pushButton_2.setEnabled(True)
        self.pushButton_2.setStyleSheet(self.qss_file)
        self.pushButton_2.setText("Start")

    def guiSave(self):
        # Save geometry
        self.addFiles_settings.setValue('size', self.size())
        # self.addFiles_settings.setValue('pos', self.pos())

        # for name, obj in inspect.getmembers(self):
            # if type(obj) is QComboBox:  # this works similar to isinstance, but
            # missed some field... not sure why?
            # if isinstance(obj, QTextBrowser):
            #     # save combobox selection to registry
            #     htmlText = obj.toHtml()
            #     self.addFiles_settings.setValue(name, htmlText)

    def guiRestore(self):

        # Restore geometry
        self.resize(self.addFiles_settings.value('size', QSize(500, 500)))
        # self.move(self.addFiles_settings.value('pos', QPoint(875, 254)))
        for name, obj in inspect.getmembers(self):
            if isinstance(obj, QComboBox):
                if name == "comboBox":
                    allItems = self.factory.fetchAllWorkFolders(self.exportPath)
                    model = obj.model()
                    obj.clear()
                    for num, i in enumerate(allItems):
                        if self.parent.isWorkFolder(i, mode="gb"):
                            text = "\"%s\" in GenBank_File (GenBank format)"%os.path.basename(i)
                        else:
                            text = "\"%s\" in Other_File" % os.path.basename(i)
                        item = QStandardItem(text)
                        item.setToolTip(i)
                        # 背景颜色
                        if num % 2 == 0:
                            item.setBackground(QColor(255, 255, 255))
                        else:
                            item.setBackground(QColor(237, 243, 254))
                        model.appendRow(item)
                    if self.parent.isWorkFolder(self.exportPath, mode="gb"):
                        obj.setCurrentText("\"%s\" in GenBank_File (GenBank format)"%os.path.basename(self.exportPath))
                    else:
                        obj.setCurrentText("\"%s\" in Other_File" % os.path.basename(self.exportPath))

    def closeEvent(self, event):
        self.interrupt = True
        if hasattr(self, "worker_download"):
            self.worker_download.stopWork()
        if hasattr(self, "progressDialog"):
            self.progressDialog.close()
        self.guiSave()

    def runProgressDialog(self, num):
        oldValue = self.progressDialog.value()
        done_int = int(num)
        if done_int > oldValue:
            self.progressDialog.setProperty("value", done_int)
            QCoreApplication.processEvents()
            if done_int == 100:
                self.progressDialog.close()

    def fetchOutputPath(self):
        index = self.comboBox.currentIndex()
        return self.comboBox.itemData(index, role=Qt.ToolTipRole)

    def downloadState(self, state):
        if state == "start":
            self.pushButton_2.setEnabled(False)  # 使之失效
            self.pushButton_2.setStyleSheet(
                'QPushButton {color: red; background-color: rgb(219, 217, 217)}')
            self.pushButton_2.setText("Downloading...")
        elif state == "stop":
            self.pushButton_2.setText("Download")
            self.pushButton_2.setStyleSheet(self.qss_file)
            self.pushButton_2.setEnabled(True)
Пример #2
0
class SerhNCBI(QMainWindow, Ui_SerhNCBI, object):
    exception_signal = pyqtSignal(str)  # 定义所有类都可以使用的信号
    updateSig = pyqtSignal(list)
    searchSig = pyqtSignal(str)
    progressBarSig = pyqtSignal(int)  # 控制进度条
    progressDiologSig = pyqtSignal(int)
    ctrlItemsSig = pyqtSignal(int)
    inputContentSig = pyqtSignal(str, str)
    downloadFinished = pyqtSignal()
    fastaDownloadFinishedSig = pyqtSignal(str)

    def __init__(self, workPath=None, parent=None):
        super(SerhNCBI, self).__init__(parent)
        # self.thisPath = os.path.dirname(os.path.realpath(__file__))
        self.parent = parent
        self.factory = Factory()
        self.thisPath = self.factory.thisPath
        self.workPath = workPath
        self.setupUi(self)
        # 保存设置
        self.serhNCBI_settings = QSettings(
            self.thisPath + '/settings/serhNCBI_settings.ini',
            QSettings.IniFormat)
        # File only, no fallback to registry or or.
        self.serhNCBI_settings.setFallbacksEnabled(False)
        # 开始装载样式表
        with open(self.thisPath + os.sep + 'style.qss',
                  encoding="utf-8",
                  errors='ignore') as f:
            self.qss_file = f.read()
        self.setStyleSheet(self.qss_file)
        # 恢复用户的设置
        self.guiRestore()
        self.exception_signal.connect(self.popupException)
        # self.progressSig.connect(self.runProgress)
        # self.logGuiSig.connect(self.addText2Log)
        self.lineEdit.buttonSearch.clicked.connect(lambda: [
            self.startSearch(),
            self.sync_completer_texts(self.lineEdit.text())
        ])
        self.lineEdit.buttonStop.clicked.connect(self.stopSearch)
        # self.lineEdit.completer().popup().show()
        # self.lineEdit.clicked.connect(lambda : self.lineEdit.completer().popup())
        self.dict_ncbi_headers = {
            "GBSeq_accession-version": "ID",
            "GBSeq_definition": "Description",
            "GBSeq_organism": "Organism",
            "GBSeq_length": "Length",
            "GBSeq_update-date": "Update date",
            "GBSeq_taxonomy": "Taxonomy",
            "GBSeq_create-date": "Create date",
            "GBSeq_moltype": "Molecular type",
            "GBSeq_topology": "Topology",
            "GBSeq_references": "References",
            "GBSeq_source": "Source",
            "GBSeq_keywords": "Keywords",
            "GBSeq_project": "Project",
            "GBSeq_other-seqids": "Other IDs",
            "GBSeq_strandedness": "Strandedness",
            "GBSeq_comment": "Comments"
        }
        self.init_list()
        self.updateSig.connect(self.updateTable)
        self.searchSig.connect(self.ctrlSearchState)
        self.progressBarSig.connect(self.searchProgress)
        self.progressDiologSig.connect(self.runProgressDialog)
        self.spinBox.valueChanged.connect(self.sync_display_items)
        self.ctrlItemsSig.connect(self.ctrlItems)
        # self.downloadFinished.connect(self.downloadDone)
        self.fastaDownloadFinishedSig.connect(self.parent.setTreeViewFocus)
        self.NCBI_model = MyNCBITableModel([self.list_table_header],
                                           parent=self)
        self.tableView.setModel(self.NCBI_model)
        header = CheckBoxHeader(parent=self.tableView)
        header.clicked.connect(self.check_displayed)
        self.tableView.setHorizontalHeader(header)
        self.NCBI_model.checkedChanged.connect(self.ctrl_text)
        self.interrupt = False
        ##下载的状态
        widget = QWidget(self)
        horizBox = QHBoxLayout(widget)
        horizBox.setContentsMargins(0, 0, 0, 0)
        spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                 QSizePolicy.Minimum)
        self.disp_check_label = QLabel(
            "<span style='font-weight:600; color:red;'>Searching...</span>",
            self)
        self.disp_check_gifLabel = QLabel(self)
        movie = QMovie(":/picture/resourses/Spinner-1s-34px.gif")
        self.disp_check_gifLabel.setMovie(movie)
        self.disp_check_progress = QProgressBar(self)
        self.disp_check_progress.setFixedWidth(100)
        movie.start()
        horizBox.addItem(spacerItem)
        horizBox.addWidget(self.disp_check_gifLabel)
        horizBox.addWidget(self.disp_check_label)
        horizBox.addWidget(self.disp_check_progress)
        self.statusbar.addPermanentWidget(widget)
        self.disp_check_label.setVisible(False)
        self.disp_check_gifLabel.setVisible(False)
        self.disp_check_progress.setVisible(False)
        self.lineEdit.installEventFilter(self)
        self.spinBox.installEventFilter(self)
        table_popMenu = QMenu(self)
        table_popMenu.setToolTipsVisible(True)
        OpenID = QAction(QIcon(":/seq_Viewer/resourses/field-Display.png"),
                         "Open in NCBI webpage",
                         self,
                         triggered=self.openID)
        OpenID.setToolTip("Open sequence in NCBI webpage")
        table_popMenu.addAction(OpenID)

        def table_popmenu(qpoint):
            if self.tableView.indexAt(qpoint).isValid():
                table_popMenu.exec_(QCursor.pos())

        self.tableView.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tableView.customContextMenuRequested.connect(table_popmenu)
        # self.tableView.horizontalHeader().resizeSection(1, 300)
        # self.tableView.horizontalHeader().resizeSection(2, 80)
        # ##增加check按钮
        # self.check_all = QCheckBox("Check/Uncheck", self)
        # self.check_all.toggled.connect(self.check_displayed)
        # self.statusbar.addWidget(self.check_all)
        ## brief demo
        self.label_6.clicked.connect(lambda: QDesktopServices.openUrl(
            QUrl(
                "https://dongzhang0725.github.io/dongzhang0725.github.io/documentation/#4-3-3-1-Brief-example"
            )))

    @pyqtSlot()
    def on_toolButton_clicked(self):
        info = '''To make use of NCBI's E-utilities, NCBI requires you to specify your email address with each request.<br> 
In case of excessive usage of the E-utilities, NCBI will attempt to contact a user at the email address provided before blocking access to the E-utilities.'''
        QMessageBox.information(
            self, "Information",
            "<p style='line-height:25px; height:25px'>%s</p>" % info)

    @pyqtSlot()
    def on_toolButton_2_clicked(self):
        #refresh
        self.interrupt = False
        self.exist_base = self.NCBI_model.rowCount(self.tableView)
        if not self.exist_base:
            return
        if hasattr(self,
                   "worker_addition") and self.worker_addition.isRunning():
            return
        if self.display_items > self.exist_base:
            self.worker_addition = WorkThread(self.addition_search,
                                              parent=self)
            self.worker_addition.start()
        # elif self.display_items < self.exist_base:
        #     list_checked = self.NCBI_model.list_checked
        #     array = self.NCBI_model.array[:self.display_items+1]
        #     self.NCBI_model = MyNCBITableModel(array, list_checked, self.tableView)
        #     self.tableView.setModel(self.NCBI_model)
        #     self.tableView.update()

    @pyqtSlot()
    def on_toolButton_3_clicked(self):
        # download
        index = self.comboBox.currentIndex()
        self.outputPath = self.comboBox.itemData(index, role=Qt.ToolTipRole)
        self.rettype = "gb" if self.parent.isWorkFolder(self.outputPath,
                                                        mode="gb") else "fasta"
        if self.rettype == "fasta":
            name, ok = QInputDialog.getText(self,
                                            'Set output file name',
                                            'Output file name:',
                                            text="sequence.fas")
            if ok:
                self.fasta_file_name = name + ".fas" if "." not in name else name
                if os.path.exists(self.outputPath + os.sep +
                                  self.fasta_file_name):
                    reply = QMessageBox.question(
                        self, "Concatenate sequence",
                        "<p style='line-height:25px; height:25px'>The file exists, replace it?</p>",
                        QMessageBox.Yes, QMessageBox.Cancel)
                    if reply == QMessageBox.Cancel:
                        return
            else:
                QMessageBox.information(
                    self, "Information",
                    "<p style='line-height:25px; height:25px'>Download canceled!</p>"
                )
                return
        if self.NCBI_model.arraydata:
            self.interrupt = False
            self.progressDialog = self.factory.myProgressDialog(
                "Please Wait", "Downloading...", parent=self)
            self.progressDialog.show()
            self.worker_download = WorkThread(self.downloadSeq, parent=self)
            self.progressDialog.canceled.connect(lambda: [
                setattr(self, "interrupt", True),
                self.worker_download.stopWork(),
                self.progressDialog.close()
            ])
            self.worker_download.finished.connect(self.downloadDone)
            self.worker_download.start()
        else:
            QMessageBox.information(
                self, "Information",
                "<p style='line-height:25px; height:25px'>Please search first!</p>"
            )

    def downloadSeq(self):
        try:
            checked_ids = self.NCBI_model.list_checked
            # if not checked_ids:
            #     checked_ids = self.NCBI_model.fetchAllIDs()
            batch_size = 20
            count = len(checked_ids) if checked_ids else self.count
            self.download_contents = ""
            for start in range(0, count, batch_size):
                if self.interrupt:
                    return
                end = min(count, start + batch_size)
                print("Going to download record %i to %i" % (start + 1, end))
                if (start + batch_size) > count:
                    batch_size = count - start
                if not checked_ids:
                    #下载所有序列的模式
                    fetch_handle = Entrez.efetch(db=self.database,
                                                 rettype=self.rettype,
                                                 retmode="text",
                                                 retstart=start,
                                                 retmax=batch_size,
                                                 webenv=self.webenv,
                                                 query_key=self.query_key)
                else:
                    fetch_handle = Entrez.efetch(db=self.database,
                                                 rettype=self.rettype,
                                                 retmode="text",
                                                 retstart=start,
                                                 retmax=batch_size,
                                                 id=checked_ids)
                self.download_contents += fetch_handle.read()
                self.progressDiologSig.emit(end * 100 / count)
            # index = self.comboBox.currentIndex()
            # filepath = self.comboBox.itemData(index, role=Qt.ToolTipRole)
            # self.downloadFinished.emit()
        except:
            self.exception_signal.emit(''.join(
                traceback.format_exception(*sys.exc_info())))

    def downloadDone(self):
        self.progressDialog.close()
        QMessageBox.information(
            self, "Download finished",
            "<p style='line-height:25px; height:25px'>Done! Back to home page to view them.</p>"
        )
        if self.rettype == "gb":
            self.inputContentSig.emit(self.download_contents, self.outputPath)
        else:
            with open(self.outputPath + os.sep + self.fasta_file_name,
                      "w",
                      encoding="utf-8") as f:
                f.write(self.download_contents)
            self.fastaDownloadFinishedSig.emit(self.outputPath)

    def startSearch(self):
        if hasattr(self, "worker") and self.worker.isRunning():
            return
        if self.spinBox.value() == 0:
            self.spinBox.setValue(20)
        if self.lineEdit.text():
            self.interrupt = False
            self.NCBI_model.init_table()  #刷新一下table(归零)
            self.worker = WorkThread(self.search, parent=self)
            self.worker.start()
        else:
            QMessageBox.information(
                self, "Search in NCBI",
                "<p style='line-height:25px; height:25px'>Please input keywords first!</p>"
            )

    def guiSave(self):
        # Save geometry
        self.serhNCBI_settings.setValue('size', self.size())
        # self.serhNCBI_settings.setValue('pos', self.pos())

        for name, obj in inspect.getmembers(self):
            # if type(obj) is QComboBox:  # this works similar to isinstance, but
            # missed some field... not sure why?
            # if isinstance(obj, QComboBox):
            #     # save combobox selection to registry
            #     text = obj.currentText()
            #     if text:
            #         allItems = [
            #             obj.itemText(i) for i in range(obj.count())]
            #         allItems.remove(text)
            #         sortItems = [text] + allItems
            #         self.serhNCBI_settings.setValue(name, sortItems)
            if isinstance(obj, QLineEdit):
                if name == "lineEdit":
                    self.serhNCBI_settings.setValue(name, self.completer_texts)
            if isinstance(obj, QSpinBox):
                if name == "spinBox":
                    self.serhNCBI_settings.setValue(name, self.display_items)

    def guiRestore(self):

        # Restore geometry
        self.resize(self.serhNCBI_settings.value('size', QSize(1000, 600)))
        self.factory.centerWindow(self)
        # self.move(self.serhNCBI_settings.value('pos', QPoint(875, 254)))

        for name, obj in inspect.getmembers(self):
            if isinstance(obj, QComboBox):
                if name == "comboBox":
                    allItems = self.factory.fetchAllWorkFolders(self.workPath)
                    model = obj.model()
                    obj.clear()
                    for num, i in enumerate(allItems):
                        if self.parent.isWorkFolder(i, mode="gb"):
                            text = "\"%s\" in GenBank_File (GenBank format)" % os.path.basename(
                                i)
                        else:
                            text = "\"%s\" in Other_File (Fasta format)" % os.path.basename(
                                i)
                        item = QStandardItem(text)
                        item.setToolTip(i)
                        # 背景颜色
                        if num % 2 == 0:
                            item.setBackground(QColor(255, 255, 255))
                        else:
                            item.setBackground(QColor(237, 243, 254))
                        model.appendRow(item)
                    # obj.setCurrentText(os.path.basename(self.workPath))
                    if self.parent.isWorkFolder(self.workPath, mode="gb"):
                        obj.setCurrentText(
                            "\"%s\" in GenBank_File (GenBank format)" %
                            os.path.basename(self.workPath))
                    else:
                        obj.setCurrentText(
                            "\"%s\" in Other_File (Fasta format)" %
                            os.path.basename(self.workPath))
            if isinstance(obj, QLineEdit):
                if name == "lineEdit":
                    self.completer_texts = self.serhNCBI_settings.value(
                        name, [])  # get stored value from registry
                    self.setLCompleter()
            if isinstance(obj, QSpinBox):
                if name == "spinBox":
                    self.display_items = int(
                        self.serhNCBI_settings.value(
                            name, 100))  # get stored value from registry
                    obj.setValue(self.display_items)

    def runProgressDialog(self, num):
        oldValue = self.progressDialog.value()
        done_int = int(num)
        if done_int > oldValue:
            self.progressDialog.setProperty("value", done_int)
            QCoreApplication.processEvents()
            if done_int == 100:
                self.progressDialog.close()

    def popupException(self, exception):
        if ("getaddrinfo failed" in exception) or ("RuntimeError"
                                                   in exception):
            text = "<p style='line-height:25px; height:25px'>Search failed, try to check your network connection!</p>"
        else:
            text = "<p style='line-height:25px; height:25px'>The search failed for some of the sequences. As this may have been  caused by a network problem, you can wait for a while and try again.<br> If the problem persists you may report it at " \
                   "<a href=\"https://github.com/dongzhang0725/PhyloSuite/issues\">https://github.com/dongzhang0725/PhyloSuite/issues</a> " \
                   "or send an email with the detailed traceback to [email protected]</p>"
        msg = QMessageBox(self)
        msg.setIcon(QMessageBox.Critical)
        msg.setText(text)
        msg.setWindowTitle("Error")
        msg.setDetailedText(exception)
        msg.setStandardButtons(QMessageBox.Ok)
        msg.exec_()

    def closeEvent(self, event):
        self.interrupt = True
        if hasattr(self, "worker") and self.worker.isRunning():
            self.worker.stopWork()
        if hasattr(self,
                   "worker_addition") and self.worker_addition.isRunning():
            self.worker_addition.stopWork()
        if hasattr(self,
                   "worker_download") and self.worker_download.isRunning():
            self.worker_download.stopWork()
        if hasattr(self, "progressDialog"):
            self.progressDialog.close()
        self.guiSave()
        # self.log_gui.close()  # 关闭子窗口

    def eventFilter(self, obj, event):
        name = obj.objectName()
        if event.type() == QEvent.KeyPress:  # 首先得判断type
            if event.key() == Qt.Key_Return:
                if name == "lineEdit":
                    self.sync_completer_texts(self.lineEdit.text())
                    self.startSearch()
                    return True
                if name == "spinBox":
                    self.on_toolButton_2_clicked()
                    return True
        # return QMainWindow.eventFilter(self, obj, event) #
        # 其他情况会返回系统默认的事件处理方法。
        return super(SerhNCBI, self).eventFilter(obj, event)  # 0

    def sync_completer_texts(self, text):
        if text and (text not in self.completer_texts):
            self.completer_texts.insert(0, text)
        if len(self.completer_texts) > 15:
            self.completer_texts = self.completer_texts[:15]
        self.guiSave()
        self.setLCompleter()

    def setLCompleter(self):
        comp = QCompleter(self.completer_texts)
        comp.setFilterMode(Qt.MatchContains)
        comp.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        # comp.popup().setStyleSheet("background-color: yellow")
        self.lineEdit.setCompleter(comp)

    def init_list(self):
        self.list_table_header = [
            "ID", "Description", "Organism", "Length", "Update date",
            "Taxonomy", "Create date", "Molecular type", "Topology",
            "References", "Source", "Keywords", "Project", "Other IDs",
            "Strandedness", "Comments"
        ]

    def updateTable(self, list_):
        # print(array)
        # 测试array是新添加的list
        self.NCBI_model.appendTable(list_)

    def ctrlSearchState(self, state):
        if state == "searching":
            self.disp_check_label.setText("Searching...")
            self.disp_check_label.setVisible(True)
            self.disp_check_gifLabel.setVisible(True)
            self.lineEdit.buttonSearch.setDisabled(True)
            self.lineEdit.buttonStop.setDisabled(False)
            self.toolButton_2.setDisabled(True)
            self.toolButton_3.setDisabled(True)
        elif state == "fetching":
            self.disp_check_label.setText("Fetching...")
            self.disp_check_label.setVisible(True)
            self.disp_check_gifLabel.setVisible(True)
            self.disp_check_progress.setValue(0)
            self.disp_check_progress.setVisible(True)
            self.lineEdit.buttonStop.setDisabled(False)
        elif state == "except":
            self.disp_check_label.setVisible(False)
            self.disp_check_gifLabel.setVisible(False)
            self.disp_check_progress.setVisible(False)
            self.lineEdit.buttonSearch.setDisabled(False)
            self.lineEdit.buttonStop.setDisabled(True)
            self.toolButton_2.setDisabled(False)
            self.toolButton_3.setDisabled(False)
        elif state == "finished":
            self.disp_check_label.setVisible(False)
            self.disp_check_gifLabel.setVisible(False)
            self.disp_check_progress.setVisible(False)
            self.lineEdit.buttonSearch.setDisabled(False)
            self.lineEdit.buttonStop.setDisabled(True)
            self.toolButton_2.setDisabled(False)
            self.toolButton_3.setDisabled(False)
            ##如果啥也没搜到
            self.exist_base = self.NCBI_model.rowCount(self.tableView)
            if not self.exist_base:
                QMessageBox.information(
                    self, "Download finished",
                    "<p style='line-height:25px; height:25px'>No items found!</p>"
                )

    def ctrlItems(self, count):
        count = count if count != 0 else 20
        self.spinBox.setMaximum(count)
        if count == 0:
            self.spinBox.setValue(20)
        self.label_4.setText("items of %s (total)" % count)
        self.label_2.setText("Download all (%s) sequences to:" % count)
        # if count < self.display_items:
        #     self.display_items = count
        #     self.spinBox.setValue(count)

    def searchProgress(self, value):
        oldValue = self.disp_check_progress.value()
        done_int = int(value)
        if done_int > oldValue:
            self.disp_check_progress.setProperty("value", done_int)
            QCoreApplication.processEvents()

    def sync_display_items(self, value):
        self.display_items = value

    def search(self):
        try:
            self.searchSig.emit("searching")
            self.init_list()
            self.ctrl_text()  #文本还原
            self.NCBI_model.list_checked = []
            self.database = self.comboBox_2.currentText()
            keywords = self.lineEdit.text()
            email = self.lineEdit_2.text()
            email = email if email else "*****@*****.**"
            Entrez.email = email
            search_handle = Entrez.esearch(db=self.database,
                                           term=keywords,
                                           usehistory="y")
            search_results = Entrez.read(search_handle)
            self.webenv = search_results["WebEnv"]
            self.query_key = search_results["QueryKey"]
            self.count = int(search_results["Count"])
            self.ctrlItemsSig.emit(
                self.count)  #如果只有2个序列,self.display_items也会变成2
            search_handle.close()
            batch_size = 20
            self.searchSig.emit("fetching")
            # time_start = time.time()
            total_displayed = self.display_items
            if self.count < total_displayed:
                total_displayed = self.count
            for start in range(0, total_displayed, batch_size):
                # try:
                if self.interrupt:
                    return
                end = min(total_displayed, start + batch_size)
                print("Going to download record %i to %i" % (start + 1, end))
                if (start + batch_size) > total_displayed:
                    batch_size = total_displayed - start
                fetch_handle = Entrez.efetch(db=self.database,
                                             retmode="xml",
                                             retstart=start,
                                             retmax=batch_size,
                                             webenv=self.webenv,
                                             query_key=self.query_key)
                fetch_records = Entrez.read(fetch_handle)
                for num, record in enumerate(fetch_records):
                    list_ = []
                    for i in [
                            "GBSeq_accession-version", "GBSeq_definition",
                            "GBSeq_organism", "GBSeq_length",
                            "GBSeq_update-date", "GBSeq_taxonomy",
                            "GBSeq_create-date", "GBSeq_moltype",
                            "GBSeq_topology", "GBSeq_references",
                            "GBSeq_source", "GBSeq_keywords", "GBSeq_project",
                            "GBSeq_other-seqids", "GBSeq_strandedness",
                            "GBSeq_comment"
                    ]:
                        if i in record:
                            list_.append(str(record[i]))
                        else:
                            list_.append("N/A")
                    self.updateSig.emit(list_)
                    self.progressBarSig.emit(
                        (start + num + 1) * 100 / total_displayed)
                fetch_handle.close()
                # except:
                #     pass
            self.searchSig.emit("finished")
        except:
            self.searchSig.emit("except")
            self.exception_signal.emit(''.join(
                traceback.format_exception(*sys.exc_info())))
        # time_end = time.time()
        # print("time:", time_end - time_start)

    def addition_search(self):
        try:
            total_displayed = self.display_items
            if self.count < total_displayed:
                total_displayed = self.count
            batch_size = 20
            self.searchSig.emit("fetching")
            for start in range(self.exist_base, total_displayed, batch_size):
                if self.interrupt:
                    break
                end = min(total_displayed, start + batch_size)
                print("Going to download record %i to %i" % (start + 1, end))
                if (start + batch_size) > total_displayed:
                    batch_size = total_displayed - start
                fetch_handle = Entrez.efetch(db=self.database,
                                             retmode="xml",
                                             retstart=start,
                                             retmax=batch_size,
                                             webenv=self.webenv,
                                             query_key=self.query_key)
                fetch_records = Entrez.read(fetch_handle)
                for num, record in enumerate(fetch_records):
                    list_ = []
                    for i in [
                            "GBSeq_accession-version", "GBSeq_definition",
                            "GBSeq_organism", "GBSeq_length",
                            "GBSeq_update-date", "GBSeq_taxonomy",
                            "GBSeq_create-date", "GBSeq_moltype",
                            "GBSeq_topology", "GBSeq_references",
                            "GBSeq_source", "GBSeq_keywords", "GBSeq_project",
                            "GBSeq_other-seqids", "GBSeq_strandedness",
                            "GBSeq_comment"
                    ]:
                        if i in record:
                            list_.append(str(record[i]))
                        else:
                            list_.append("N/A")
                    self.updateSig.emit(list_)
                    self.progressBarSig.emit(
                        (start - self.exist_base + num + 1) * 100 /
                        (total_displayed - self.exist_base))
                # self.progressBarSig.emit((start - self.exist_base)*100/(total_displayed - self.exist_base))
                fetch_handle.close()
            self.searchSig.emit("finished")
        except:
            self.searchSig.emit("except")
            self.exception_signal.emit(''.join(
                traceback.format_exception(*sys.exc_info())))

    def ctrl_text(self):
        selected_num = len(self.NCBI_model.list_checked)
        if selected_num:
            self.label_2.setText("Download selected (%d) sequences to:" %
                                 (selected_num))
        else:
            text = "Download all (%d) sequences to:" % self.count if hasattr(
                self, "count") else "Download all sequences to:"
            self.label_2.setText(text)

    def openID(self):
        indices = self.tableView.selectedIndexes()
        arraydata = self.NCBI_model.arraydata
        ID = arraydata[indices[0].row()][0].text()
        url = "https://www.ncbi.nlm.nih.gov/nuccore/%s"%ID if self.comboBox_2.currentText() == "nucleotide" \
            else "https://www.ncbi.nlm.nih.gov/protein/%s"%ID
        QDesktopServices.openUrl(QUrl(url))

    def stopSearch(self):
        self.interrupt = True
        if hasattr(self, "worker") and self.worker.isRunning():
            self.worker.stopWork()
        if hasattr(self,
                   "worker_addition") and self.worker_addition.isRunning():
            self.worker_addition.stopWork()
        self.searchSig.emit("except")

    def check_displayed(self, isCheck):
        if hasattr(self, "NCBI_model") and self.NCBI_model.rowCount(
                self.tableView):
            # self.NCBI_model.beginResetModel()
            self.NCBI_model.layoutAboutToBeChanged.emit()
            if isCheck:
                self.NCBI_model.list_checked = [
                    i[0].text() for i in self.NCBI_model.arraydata
                ]
            else:
                self.NCBI_model.list_checked = []
            self.NCBI_model.layoutChanged.emit()
            self.ctrl_text()