Exemplo n.º 1
0
class ExtendedLineEdit(QLineEdit):
    signal_send_movie = pyqtSignal(list)
    signal_search_movie = pyqtSignal(str)
    signal_request_movie_data = pyqtSignal(int)
    signal_set_loading = pyqtSignal(str, bool)

    DEBUG = False

    def __init__(self, parent=None):
        super(ExtendedLineEdit, self).__init__(parent)
        self.movies = []

        self.completer_lw = QListWidget()
        self.model = self.completer_lw.model()

        self.completer = QCompleter(self.model, self)
        self.completer.setPopup(self.completer_lw)
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.completer.setCompletionRole(
            Qt.UserRole
        )  # Change role because default EditRole is paited to list somehow
        self.setCompleter(self.completer)

        self.textEdited.connect(self.text_edited)
        #self.completer.activated[QModelIndex].connect(self.on_completer_activated)
        #self.completer.activated[str].connect(self.on_completer_activated_str)
        self.completer_lw.itemClicked.connect(self.item_clicked)

        self.installEventFilter(self)

    def eventFilter(self, obj, event):
        if event.type() == QEvent.MouseButtonPress:
            if event.button() == Qt.LeftButton:
                self.completer.complete()
        return super(ExtendedLineEdit, self).eventFilter(obj, event)

    def setText(self, text: str) -> None:
        if self.DEBUG: print('setText', text, self.sender())
        super(ExtendedLineEdit, self).setText(text)
        if not isinstance(self.sender(), QCompleter) and text:
            self.text_edited(text)

    @pyqtSlot(list)
    def update_movies_list(self, result):
        if self.DEBUG: print('update_movies_list', result[0], len(result) - 1)
        type = result.pop(0)

        if type == 'db':
            self.movies = [x + [
                type,
            ] for x in result]
            self.completer_lw.clear()
            self.completer.complete()
        else:
            for item in result:
                self.movies.append(item + [
                    type,
                ])

        for item in result:
            cwidget = MyWidget()
            cwidget.label_movie_name.setText(item[1] if item[1] else item[2])
            cwidget.label_original_name.setText(item[2])
            cwidget.label_source.setText(type)
            cwidget.label_year.setText(str(item[3]))

            completer_myQListWidgetItem = QListWidgetItem(self.completer_lw)
            completer_myQListWidgetItem.setSizeHint(cwidget.sizeHint())
            completer_myQListWidgetItem.setData(Qt.UserRole, item[1])
            self.completer_lw.addItem(completer_myQListWidgetItem)
            self.completer_lw.setItemWidget(completer_myQListWidgetItem,
                                            cwidget)

        if self.hasFocus() and not self.completer_lw.isVisible() and len(
                self.movies) > 0:
            self.completer.complete()

    @pyqtSlot(str)
    def text_edited(self, text):
        if self.DEBUG: print('text_edited', text, self.sender())
        if text and isinstance(self.sender(), ExtendedLineEdit):
            self.signal_search_movie.emit(text)

    @pyqtSlot(str)
    def on_completer_activated_str(self, name: str):
        if self.DEBUG: print('on_completer_activated_str', name)

    @pyqtSlot(QModelIndex)
    def on_completer_activated(self, index: QModelIndex):
        if self.DEBUG: print('on_completer_activated', index.row())
        item = self.movies[index.row()]

        if len(item) > 13:
            self.signal_send_movie.emit(item[:13])
            self.signal_request_movie_data.emit(item[13])
        else:
            self.signal_send_movie.emit(item)

    @pyqtSlot(QListWidgetItem)
    def item_clicked(self, item: QListWidgetItem):
        if self.DEBUG: print('item_clicked', item, [i[1] for i in self.movies])
        index = self.completer_lw.indexFromItem(item)
        item = self.movies[index.row()]
        type = item[-1]

        if type == 'db':
            self.signal_send_movie.emit(item)
        else:
            self.signal_set_loading.emit('movie', True)

            if len(item) > 13:
                self.signal_send_movie.emit(item[:13])
                self.signal_request_movie_data.emit(item[13])
            else:
                self.signal_send_movie.emit(item)

    def reset(self):
        if self.DEBUG: print('reset')
        self.completer_lw.clear()
        self.clearFocus()
Exemplo n.º 2
0
class FileRenameWidget(QWidget):
    """
    给文件加后缀例子:(^[^\.]+) 替换成\1_26
    """
    class ReplaceTemplateWidget(QWidget):
        def __init__(self, parent=None, **kwargs):
            super().__init__(parent, **kwargs)

    def __init__(self, parent=None, **kwargs):
        super().__init__(parent, **kwargs)
        self.fileDir = ""
        self.fileDragList = []
        self.fileList = []
        self.filterRe = ""
        self.dirDeepSearch = False
        self.filterUseRe = False
        self.replaceUseRe = False

        self.fileDirLineEdit = FileOpenDirLineEdit()
        self.dirDeepSearchCheckBox = QCheckBox("递归搜素目录")
        self.filterReLineEdit = QLineEdit(minimumWidth=240)
        self.filterUseReCheckBox = QCheckBox("使用re")
        self.replaceTmpBtn = QPushButton("模板")#"<span style='color:blue'>模板</span>"
        self.replaceOldLineEdit = QLineEdit(minimumWidth=240)
        self.replaceNewLineEdit = QLineEdit(minimumWidth=240)
        self.replaceUseReCheckBox = QCheckBox("使用re")
        self.execButton = QPushButton("execute(执行)", maximumWidth=100)
        self.replacePromptLabel = QLabel()
        self.fileListText = DragLineTextEdit()

        gridLayout = GridLayout(self, contentsMargins=(10, 10, 10, 10), spacing=10)
        replaceLayout = HBoxLayout(contentsMargins=(0, 10, 10, 10), spacing=10,
                            widgets=[self.replaceOldLineEdit, QLabel("替换成"), self.replaceNewLineEdit,
                                     self.replaceUseReCheckBox, self.replaceTmpBtn,LayStretch(1)])
        glWidgets = [
            [GLItem(QLabel("目录:"), 1, 2), GLItem(self.fileDirLineEdit, 1, 4), GLItem(self.dirDeepSearchCheckBox, 1, 2),GLItem(QWidget(), 1, -1)],
            [GLItem(QLabel("过滤字符串:"), 1, 2), GLItem(self.filterReLineEdit, 1, 3), GLItem(self.filterUseReCheckBox, 1, 2),GLItem(QWidget(), 1, 3)],
            [GLItem(QLabel("替换:"), 1, 2),GLItem(replaceLayout, 1, -1)],
            [GLItem(self.execButton, 1, 2), GLItem(self.replacePromptLabel, 1, -1)],
            [GLItem(self.fileListText, 1, -1)]
        ]
        gridLayout.addWidgets(glWidgets)

        self.replaceTmpWidget = QListWidget(self)
        self.replaceTmpList = [{"text":"添加后缀","name":"add_suffix"}]
        self.replaceTmpWidget.addItems(replaceTmp['text'] for replaceTmp in self.replaceTmpList)
        self.replaceTmpWidget.resize(100, 300)
        self.replaceTmpWidget.hide()

        # 注册事件
        self.registerSignalConnect()

    def registerSignalConnect(self):
        self.fileDirLineEdit.textChanged.connect(self.fileDirChanged)
        # self.filterReLineEdit.textChanged.connect(self.filterReChanged)
        # 回车触发事件(只输入\,re.compile会报错)
        self.filterReLineEdit.returnPressed.connect(self.filterReConfirm)
        self.replaceNewLineEdit.returnPressed.connect(lambda : self._setAllFileList())
        self.fileListText.dragSignal.connect(self.fileDrag)
        """
        复选框的三种状态:
        Qt.Checked:2, 组件没有被选中(默认)
        Qt.PartiallyChecked1:, 组件被半选中
        Qt.Unchecked:0, 组件被选中
        """
        #当一个信号与多个槽函数关联时,槽函数按照建立连接时的顺序依次执行。(我测试过确实是,网上有些人说的不对)
        #self.filterUseReCheckBox.stateChanged.connect(lambda state: print("111111111"))
        #self.filterUseReCheckBox.stateChanged.connect(lambda state: print("222222222"))
        self.dirDeepSearchCheckBox.stateChanged.connect(lambda state: setattr(self, "dirDeepSearch", state > 0))
        self.dirDeepSearchCheckBox.stateChanged.connect(lambda state: self._setFileList())
        self.filterUseReCheckBox.stateChanged.connect(lambda state: setattr(self, "filterUseRe", state>0) )
        self.filterUseReCheckBox.stateChanged.connect(lambda state: self._setFileList())
        self.replaceUseReCheckBox.stateChanged.connect(lambda state: setattr(self, "replaceUseRe", state>0) )
        self.replaceUseReCheckBox.stateChanged.connect(lambda state: self._setFileList())
        self.execButton.clicked.connect(self.execButtonClicked)

        self.replaceTmpBtn.clicked.connect(self.replaceTmpBtnClicked)
        self.replaceTmpWidget.itemClicked.connect(self.replaceTmpClicked)

    def replaceTmpBtnClicked(self,*param):
        if self.replaceTmpWidget.isVisible():
            self.replaceTmpWidget.hide()
        else:
            #获取纵坐标,obj.y(),包括框架。如果没有父控件是相对于桌面坐标。
            self.replaceTmpWidget.move(self.width()-100, self.replaceTmpBtn.y()+ self.replaceTmpBtn.height())
            self.replaceTmpWidget.show()
            self.replaceTmpWidget.raise_()

    def replaceTmpClicked(self,item):
        replaceTmp = self.replaceTmpList[self.replaceTmpWidget.currentRow()]
        if replaceTmp["name"] == "add_suffix":
            self.replaceOldLineEdit.setText(r"(^[^\.]+)")
            self.replaceNewLineEdit.setText(r"\1_26")
            self.replaceUseReCheckBox.setChecked(True)

        self.replaceTmpWidget.hide()

    def fileDrag(self, links):
        for link in links:
            #python集合的+=要求右边是是可迭代对象
            #self.fileDragList += link
            self.fileDragList.append(link)

        self._setAllFileList()

    def _getReplacePrompt(self, fileList):
        if len(fileList) == 0:
            self.replacePromptLabel.setText("")
        else:
            _,fileName = os.path.split(fileList[0])
            fmt = "<span style='color:#02AC03;font-size:18px;'>{}</span> 修改成:<span style='color:#02AC03;font-size:18px;'>{}</span>"
            if not self.replaceUseRe:
                self.replacePromptLabel.setText(fmt.format(fileName, fileName.replace(self.replaceOldLineEdit.text(),  self.replaceNewLineEdit.text())))
            else:
                self.replacePromptLabel.setText(fmt.format(fileName,
                                                                   re.sub(self.replaceOldLineEdit.text(), self.replaceNewLineEdit.text(), fileName) ))
    def _getAllFileList(self):
        if len(self.fileDragList) == 0:
            return self.fileList

        fileSet = set(self.fileList)
        fileList = [file for file in self.fileList]
        for file in self.fileDragList:
            if file in fileSet:
                continue
            fileList.append(file)
            fileSet.add(file)

        return fileList

    def _setAllFileList(self):
        fileList = self._getAllFileList()

        self._getReplacePrompt(fileList)
        self.fileListText.setPlainText("\n".join(fileList))

    def execButtonClicked(self, *params):
        reply = QMessageBox.information(self, '提示', '确定要修改文件名吗?', QMessageBox.Ok | QMessageBox.No,
                                        QMessageBox.No)
        if reply != QMessageBox.Ok:
            return

        old = self.replaceOldLineEdit.text()
        new = self.replaceNewLineEdit.text()

        for dirname, filename in (os.path.split(path) for path in self._getAllFileList()):
            if not self.replaceUseRe:
                newname = filename.replace(old, new)
            else:
                newname = re.sub(old, new, filename)
            if filename != newname:
                os.rename(os.path.join(dirname, filename), os.path.join(dirname, newname))

        self.fileDragList.clear()
        self._setFileList()


    def fileDirChanged(self, fileDir):
        self.fileDir = fileDir
        self._setFileList()

    def filterReChanged(self, filterRe):
        self.filterRe = filterRe
        self._setFileList()

    def filterReConfirm(self):
        self.filterRe = self.filterReLineEdit.text()
        self._setFileList()

    def _setFileList(self):
        self.fileList.clear()
        if not os.path.isdir(self.fileDir):
            return

        try:
            if self.filterUseRe:
                filterRe = re.compile(self.filterRe)
        except Exception as e:
            """如果输入\,re.compile会报错"""
            #打印堆栈信息
            #traceback.print_exc()
            # 或者得到堆栈字符串信息
            info = traceback.format_exc()
            print(info)
            return

        first = True
        for parent, dirnames, filenames in os.walk(self.fileDir):
            #只搜索一层
            if not self.dirDeepSearch and not first:
                break
            first = False
            for filename in filenames:
                if self.filterUseRe:
                    if filterRe.search(filename) is None:
                        continue
                else:
                    if self.filterRe not in filename:
                        continue
                self.fileList.append(os.path.join(parent, filename))  # 路径和文件名连接构成完整路径

        self._setAllFileList()