From 31354800c175babbef557f9fdc7600c7cbca8989 Mon Sep 17 00:00:00 2001 From: Ceyase Date: Sun, 26 Jan 2025 15:24:31 +0800 Subject: [PATCH] FileExplorer Search Support --- editors/gm/gm_strings_editor.py | 20 ++++++--- main_window.py | 2 +- widgets/file_explorer.py | 79 +++++++++++++++++++++++++++++++-- 3 files changed, 91 insertions(+), 10 deletions(-) diff --git a/editors/gm/gm_strings_editor.py b/editors/gm/gm_strings_editor.py index c3c2021..ea0c7ff 100644 --- a/editors/gm/gm_strings_editor.py +++ b/editors/gm/gm_strings_editor.py @@ -1,4 +1,4 @@ -from PySide6.QtWidgets import QHBoxLayout, QPlainTextEdit +from PySide6.QtWidgets import QHBoxLayout, QPlainTextEdit, QVBoxLayout, QLabel from .gm_base_editor import BaseEditor from modules.UML import GameMakerLib as gml @@ -10,21 +10,29 @@ def _handle_modify(self): def init_ui(self): layout = QHBoxLayout(self) + # 源文本侧布局 + source_layout = QVBoxLayout() + source_layout.addWidget(QLabel("源文本")) self.source_editor = QPlainTextEdit() try: self.source_editor.setPlainText(self.source_data.Strings[int(self.id)].Content) except: - self.source_editor.setPlainText("无法读取源文件") + self.source_editor.setPlainText("无法读取源文本") self.source_editor.setReadOnly(True) - + source_layout.addWidget(self.source_editor) + + # 目标文本侧布局 + target_layout = QVBoxLayout() + target_layout.addWidget(QLabel("目标文本")) self.target_editor = QPlainTextEdit() try: self.target_editor.setPlainText(self.target_data.Strings[int(self.id)].Content) except: self.target_editor.setPlainText("") - - layout.addWidget(self.source_editor) - layout.addWidget(self.target_editor) + target_layout.addWidget(self.target_editor) + + layout.addLayout(source_layout) + layout.addLayout(target_layout) self.target_editor.textChanged.connect(self._handle_modify) diff --git a/main_window.py b/main_window.py index ad7e757..4408de9 100644 --- a/main_window.py +++ b/main_window.py @@ -75,7 +75,7 @@ def init_ui(self): self.file_explorer = FileExplorer() self.file_explorer.file_double_clicked.connect(self.open_file) self.menu_bar.file_explorer_action.connect(self.file_explorer.show_or_close) - self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.file_explorer) + self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.file_explorer) # 初始化工具栏 self.tool_bar = MainToolBar() diff --git a/widgets/file_explorer.py b/widgets/file_explorer.py index 04505c1..b61c3d2 100644 --- a/widgets/file_explorer.py +++ b/widgets/file_explorer.py @@ -1,6 +1,8 @@ -from PySide6.QtWidgets import QDockWidget, QTreeWidget, QTreeWidgetItem +from PySide6.QtWidgets import (QDockWidget, QTreeWidget, QTreeWidgetItem, + QLineEdit, QCheckBox, QHBoxLayout, QVBoxLayout, QWidget) from PySide6.QtCore import Qt, Signal import os +import re class FileExplorer(QDockWidget): file_double_clicked = Signal(str) # 发送相对路径 @@ -8,10 +10,81 @@ class FileExplorer(QDockWidget): def __init__(self, parent=None): super().__init__("文件浏览器", parent) self.data = [{},{}] + + # 创建搜索组件 + self.search_line = QLineEdit() + self.search_line.setPlaceholderText("搜索...") + self.regex_checkbox = QCheckBox("正则表达式") + + # 创建布局 + search_layout = QHBoxLayout() + search_layout.addWidget(self.search_line) + search_layout.addWidget(self.regex_checkbox) + + # 创建树部件 self.tree = QTreeWidget() self.tree.setHeaderLabel("项目文件") self.tree.itemDoubleClicked.connect(self.on_item_double_clicked) - self.setWidget(self.tree) + + # 主容器布局 + container = QWidget() + main_layout = QVBoxLayout(container) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.addLayout(search_layout) + main_layout.addWidget(self.tree) + self.setWidget(container) + + # 连接信号 + self.search_line.textChanged.connect(self.update_filter) + self.regex_checkbox.stateChanged.connect(self.update_filter) + + def update_filter(self): + """更新树形结构的过滤状态""" + search_text = self.search_line.text() + use_regex = self.regex_checkbox.isChecked() + self.filter_items(search_text, use_regex) + + def filter_items(self, text, use_regex): + """过滤树形结构项""" + try: + pattern = re.compile(text, re.IGNORECASE) if use_regex and text else None + except re.error: + return # 忽略无效的正则表达式 + + root = self.tree.invisibleRootItem() + for i in range(root.childCount()): + item = root.child(i) + self._filter_item(item, text, pattern, use_regex) + + def _filter_item(self, item, text, pattern, use_regex): + """递归过滤树节点""" + child_visible = False + # 先处理子节点 + for i in range(item.childCount()): + child = item.child(i) + if self._filter_item(child, text, pattern, use_regex): + child_visible = True + + # 检查当前节点是否匹配 + match = False + if not text: # 空搜索字符串显示所有 + match = True + else: + item_text = item.text(0) + if use_regex and pattern: + match = bool(pattern.search(item_text)) + else: + match = text.lower() in item_text.lower() + + # 显示逻辑:自身匹配或子节点可见 + is_visible = match or child_visible + item.setHidden(not is_visible) + + # 展开匹配的父节点 + if is_visible and item.parent(): + item.parent().setExpanded(True) + + return is_visible def on_item_double_clicked(self, item): if not item.childCount(): @@ -26,6 +99,7 @@ def load_project(self, project_data): source_dir = project_data['source'] self._populate_tree(self.tree, source_dir, project_data) + self.tree.expandToDepth(1) # 默认展开一级目录 def _populate_tree(self, parent, path, base_data): for item_name in sorted(os.listdir(path)): @@ -51,7 +125,6 @@ def _populate_tree_gm(self, parent, path, base_data): node = QTreeWidgetItem(pnode) node.setText(0, str(self.data[0][rel_path].Strings[i])) node.setData(0, Qt.ItemDataRole.UserRole, f"gm:{rel_path}/GMStrings/{i}") - def show_or_close(self): if self.isVisible():