This commit is contained in:
2025-11-02 19:17:20 +08:00
parent ebf784146e
commit e71b69db5f
2575 changed files with 1242294 additions and 95 deletions

View File

@@ -1,5 +1,6 @@
# coding: utf-8
import re
from loguru import logger
from PyQt6.QtCore import Qt, pyqtSignal
from PyQt6.QtGui import QPixmap
@@ -8,7 +9,7 @@ from qfluentwidgets import Action, BodyLabel, CardWidget, ImageLabel, InfoBar, I
MessageBox, PushButton, RoundMenu, StrongBodyLabel
from qfluentwidgets import FluentIcon as FIF
from app.core import (DeleteFileThread, formatDate, formatSize, getFileIcon, lang, signalBus)
from app.core import (DeleteFileThread, RenameFileThread, formatDate, formatSize, getFileIcon, lang, signalBus)
from app.view.widgets.share_file_messageBox import ShareFileMessageBox
@@ -132,6 +133,9 @@ class FileCard(CardWidget):
Action(
FIF.PROJECTOR, lang("预览"), triggered=lambda: self.selfPreview()
),
Action(
FIF.EDIT, lang("重命名"), triggered=lambda: self.renameSelf()
),
]
)
@@ -151,6 +155,9 @@ class FileCard(CardWidget):
menu.addActions(
[
Action(FIF.DOWNLOAD, lang("进入"), triggered=lambda: self.dirClicked()),
Action(
FIF.EDIT, lang("重命名"), triggered=lambda: self.renameSelf()
),
]
)
@@ -171,31 +178,47 @@ class FileCard(CardWidget):
)
if w.exec():
# 构建Cloudreve V4 API所需的正确路径格式
if self.filePath == "/":
# 确保路径格式规范避免Path not exist错误
# 只使用路径中的目录部分,不包含文件名,确保不会重复
dir_path = self.filePath
if dir_path == "/":
# 根目录情况
full_path = f"cloudreve://my/{self.fileName}"
else:
# 子目录情况,确保正确拼接路径
# 清理路径,避免重复的斜杠和前缀
clean_path = self.filePath.lstrip("/")
# 确保路径中不包含cloudreve://my前缀
clean_path = clean_path.replace("cloudreve://my/", "")
full_path = f"cloudreve://my/{clean_path}/{self.fileName}"
# 子目录情况,确保只使用目录路径
# 清理路径,移除协议前缀
clean_dir = dir_path
if clean_dir.startswith("cloudreve://my/"):
clean_dir = clean_dir[15:] # 移除 "cloudreve://my/"
elif clean_dir.startswith("/"):
clean_dir = clean_dir[1:] # 移除前导斜杠
# 确保路径格式正确,移除重复的前缀
full_path = full_path.replace("cloudreve://my/cloudreve://my", "cloudreve://my")
# 确保路径中间没有多余的斜杠
clean_dir = '/'.join([part for part in clean_dir.split('/') if part])
# 更健壮地处理重复文件名的情况
# 分割路径并去重
# 构建完整URI只包含目录路径和文件名一次
full_path = f"cloudreve://my/{clean_dir}/{self.fileName}"
# 检查并移除可能的重复文件名部分
# 避免同时包含编码形式和原始形式的文件名
import re
# 查找可能的编码形式+原始形式的重复模式
path_parts = full_path.split('/')
if len(path_parts) > 1:
# 检查最后个部分是否是文件名
if path_parts[-1] == self.fileName:
# 检查倒数第二个部分是否也是文件名
if len(path_parts) > 2 and path_parts[-2] == self.fileName:
# 移除重复的文件名部分
path_parts.pop(-2)
full_path = '/'.join(path_parts)
if len(path_parts) > 3:
# 检查最后个部分是否可能是编码和原始形式的关系
potential_encoding = path_parts[-2]
original = path_parts[-1]
# 如果倒数第二个部分看起来像URL编码且最后一个部分是中文
if re.match(r'^%[0-9A-Fa-f]{2}%[0-9A-Fa-f]{2}%[0-9A-Fa-f]{2}%[0-9A-Fa-f]{2}$', potential_encoding) and any('\u4e00'-'\u9fff' in c for c in original):
# 移除倒数第二个部分,避免重复
path_parts.pop(-2)
full_path = '/'.join(path_parts)
# 最终清理
full_path = full_path.replace("//", "/") # 移除多余的斜杠
# 记录构建的路径用于调试
print(f"[DEBUG] 重命名路径: {full_path}")
self.deleteThread = DeleteFileThread(full_path, self.fileType)
self.deleteThread.successDelete.connect(self.deleteSuccess)
@@ -235,6 +258,162 @@ class FileCard(CardWidget):
self.window(),
)
logger.error(f"删除文件失败:{error_msg}")
def renameSelf(self):
"""重命名文件或文件夹"""
# 使用输入对话框获取新名称
from qfluentwidgets import LineEdit, MessageBoxBase, SubtitleLabel
from PyQt6.QtCore import Qt
import re
# 创建自定义对话框
class RenameMessageBox(MessageBoxBase):
"""自定义重命名对话框"""
def __init__(self, parent=None, initial_name=""):
super().__init__(parent)
self.titleLabel = SubtitleLabel(f"{lang("请输入新名称")}:")
self.lineEdit = LineEdit()
self.lineEdit.setText(initial_name)
# 选择文件名部分(不包括扩展名)
if "." in initial_name:
name_part = initial_name.rsplit(".", 1)[0]
self.lineEdit.setSelection(0, len(name_part))
else:
self.lineEdit.selectAll()
# 将组件添加到布局中
self.viewLayout.addWidget(self.titleLabel)
self.viewLayout.addWidget(self.lineEdit)
# 设置对话框的最小宽度
self.widget.setMinimumWidth(400)
# 设置窗口标题
self.setWindowTitle(lang("重命名"))
# 创建并显示对话框
dlg = RenameMessageBox(self.window(), self.fileName)
if dlg.exec():
new_name = dlg.lineEdit.text().strip()
# 验证文件名
if not new_name:
InfoBar.warning(
lang("警告"),
lang("文件名不能为空"),
Qt.Orientation.Horizontal,
True,
1000,
InfoBarPosition.TOP_RIGHT,
self.window(),
)
return
# 检查文件名是否包含无效字符
if re.search(r'[<>"/\\|?*]', new_name):
InfoBar.warning(
lang("警告"),
lang("文件名包含无效字符"),
Qt.Orientation.Horizontal,
True,
1000,
InfoBarPosition.TOP_RIGHT,
self.window(),
)
return
# 检查文件名是否与当前目录中的其他文件重复
# 获取当前目录下的所有文件名称
current_folder = self.filePath
# 从父窗口获取文件列表假设父窗口有fileList属性
parent_window = self.window()
if hasattr(parent_window, 'fileList'):
# 遍历文件列表,检查是否有相同名称的文件(排除当前正在重命名的文件)
for file_item in parent_window.fileList:
# 跳过当前正在重命名的文件
if hasattr(file_item, 'fileName') and file_item.fileName == self.fileName:
continue
# 检查是否有同名文件
if hasattr(file_item, 'fileName') and file_item.fileName == new_name:
InfoBar.warning(
lang("警告"),
lang("文件名已存在"),
Qt.Orientation.Horizontal,
True,
1000,
InfoBarPosition.TOP_RIGHT,
self.window(),
)
return
# 构建Cloudreve V4 API所需的正确路径格式
# 确保路径格式规范避免Path not exist错误
# 只使用路径中的目录部分,不包含文件名
if self.filePath == "/":
# 根目录情况URI只包含根目录路径
full_path = "cloudreve://my" # 直接使用正确的双斜杠格式
else:
# 子目录情况,确保只使用目录路径,不包含文件名
# 清理路径,移除协议前缀
clean_path = self.filePath
if clean_path.startswith("cloudreve://my/"):
clean_path = clean_path[15:] # 移除 "cloudreve://my/"
elif clean_path.startswith("/"):
clean_path = clean_path[1:] # 移除前导斜杠
# 构建完整URI只包含目录路径
full_path = f"cloudreve://my/{clean_path}" # 直接使用正确的双斜杠格式
# 强制确保协议前缀格式正确,使用双斜杠
# 直接替换所有可能的单斜杠格式
full_path = full_path.replace("cloudreve:/my", "cloudreve://my")
full_path = full_path.replace("cloudreve:/", "cloudreve://")
# 再次确认格式完全正确
if not full_path.startswith("cloudreve://"):
# 如果格式仍然不正确重新构建整个URI
path_part = full_path.replace("cloudreve:", "").lstrip("/")
full_path = f"cloudreve://{path_part}"
# 不再需要处理文件名重复因为URI中只包含目录路径
# 最终清理
full_path = full_path.replace("//", "/") # 移除多余的斜杠
# 记录构建的路径用于调试
print(f"[DEBUG] 重命名路径: {full_path}")
# 调用重命名线程
self.renameThread = RenameFileThread(full_path, new_name, self.fileType)
self.renameThread.successRename.connect(self.renameSuccess)
self.renameThread.errorRename.connect(self.renameError)
self.renameThread.start()
def renameSuccess(self):
InfoBar.success(
lang("成功"),
lang("重命名成功"),
Qt.Orientation.Horizontal,
True,
1000,
InfoBarPosition.TOP_RIGHT,
self.window(),
)
# 刷新文件夹列表
signalBus.refreshFolderListSignal.emit()
def renameError(self, error_msg):
InfoBar.error(
lang("失败"),
f"{lang("重命名失败")}: {error_msg}",
Qt.Orientation.Horizontal,
True,
1000,
InfoBarPosition.TOP_RIGHT,
self.window(),
)
logger.error(f"重命名文件失败:{error_msg}")
def contextMenuEvent(self, e):
"""重写上下文菜单事件,确保只有右键点击才会触发"""