mirror of
https://github.com/HChaZZY/Any2MIF.git
synced 2025-12-06 10:33:49 +08:00
254 lines
9.2 KiB
Python
254 lines
9.2 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
# Copyright (c) 2025 Any2MIF Project
|
|
# All rights reserved.
|
|
|
|
"""
|
|
Any2MIF - 文件选择模块
|
|
负责文件的选择和管理
|
|
"""
|
|
|
|
import os
|
|
from PyQt6.QtWidgets import (
|
|
QWidget, QVBoxLayout, QHBoxLayout, QPushButton,
|
|
QListWidget, QListWidgetItem, QFileDialog, QLabel,
|
|
QMenu, QAbstractItemView
|
|
)
|
|
from PyQt6.QtCore import Qt, QSettings, pyqtSignal
|
|
from PyQt6.QtGui import QIcon, QDragEnterEvent, QDropEvent
|
|
|
|
class FileSelector(QWidget):
|
|
"""文件选择器组件"""
|
|
|
|
# 自定义信号
|
|
file_selected = pyqtSignal(str) # 文件被选择时发出的信号
|
|
convert_clicked = pyqtSignal() # 转换按钮被点击时发出的信号
|
|
batch_convert_clicked = pyqtSignal() # 批量转换按钮被点击时发出的信号
|
|
|
|
def __init__(self, settings: QSettings, parent=None):
|
|
"""初始化文件选择器"""
|
|
super().__init__(parent)
|
|
self.settings = settings
|
|
self.recent_files = self.settings.value("recent_files", [])
|
|
if not isinstance(self.recent_files, list):
|
|
self.recent_files = []
|
|
|
|
self._init_ui()
|
|
self._load_recent_files()
|
|
|
|
def _init_ui(self):
|
|
"""初始化UI"""
|
|
# 设置接受拖放
|
|
self.setAcceptDrops(True)
|
|
|
|
# 创建主布局
|
|
layout = QVBoxLayout(self)
|
|
layout.setContentsMargins(0, 0, 0, 0)
|
|
|
|
# 创建标题标签
|
|
title_label = QLabel("文件选择")
|
|
title_label.setStyleSheet("font-weight: bold; font-size: 14px;")
|
|
layout.addWidget(title_label)
|
|
|
|
# 创建文件列表
|
|
self.file_list = QListWidget()
|
|
self.file_list.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
|
|
self.file_list.itemDoubleClicked.connect(self._on_item_double_clicked)
|
|
self.file_list.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
|
self.file_list.customContextMenuRequested.connect(self._show_context_menu)
|
|
layout.addWidget(self.file_list)
|
|
|
|
# 创建按钮容器
|
|
button_container = QWidget()
|
|
button_container_layout = QVBoxLayout(button_container)
|
|
button_container_layout.setContentsMargins(0, 0, 0, 0)
|
|
button_container_layout.setSpacing(5)
|
|
layout.addWidget(button_container)
|
|
|
|
# 创建上方按钮布局
|
|
top_button_layout = QHBoxLayout()
|
|
top_button_layout.setContentsMargins(0, 0, 0, 0)
|
|
button_container_layout.addLayout(top_button_layout)
|
|
|
|
# 添加文件按钮
|
|
self.add_file_button = QPushButton("添加文件")
|
|
self.add_file_button.clicked.connect(self._add_files)
|
|
top_button_layout.addWidget(self.add_file_button)
|
|
|
|
# 添加文件夹按钮
|
|
self.add_folder_button = QPushButton("添加文件夹")
|
|
self.add_folder_button.clicked.connect(self._add_folder)
|
|
top_button_layout.addWidget(self.add_folder_button)
|
|
|
|
# 清除按钮
|
|
self.clear_button = QPushButton("清除")
|
|
self.clear_button.clicked.connect(self._clear_files)
|
|
top_button_layout.addWidget(self.clear_button)
|
|
|
|
# 创建下方按钮布局(转换和批量转换按钮)
|
|
bottom_button_layout = QHBoxLayout()
|
|
bottom_button_layout.setContentsMargins(0, 0, 0, 0)
|
|
button_container_layout.addLayout(bottom_button_layout)
|
|
|
|
# 转换按钮
|
|
self.convert_button = QPushButton("转换")
|
|
self.convert_button.clicked.connect(self._on_convert_clicked)
|
|
bottom_button_layout.addWidget(self.convert_button)
|
|
|
|
# 批量转换按钮
|
|
self.batch_convert_button = QPushButton("批量转换")
|
|
self.batch_convert_button.clicked.connect(self._on_batch_convert_clicked)
|
|
bottom_button_layout.addWidget(self.batch_convert_button)
|
|
|
|
# 确保两行按钮的总宽度相同
|
|
# 为上面三个按钮设置相同的最小宽度
|
|
min_width = 80
|
|
self.add_file_button.setMinimumWidth(min_width)
|
|
self.add_folder_button.setMinimumWidth(min_width)
|
|
self.clear_button.setMinimumWidth(min_width)
|
|
|
|
# 为下面两个按钮设置宽度,使它们的总宽度与上面三个按钮相同
|
|
convert_width = (min_width * 3) // 2
|
|
self.convert_button.setMinimumWidth(convert_width)
|
|
self.batch_convert_button.setMinimumWidth(convert_width)
|
|
|
|
def _load_recent_files(self):
|
|
"""加载最近使用的文件"""
|
|
for file_path in self.recent_files:
|
|
if os.path.exists(file_path):
|
|
self._add_file_to_list(file_path)
|
|
|
|
def _add_file_to_list(self, file_path):
|
|
"""将文件添加到列表中"""
|
|
# 检查文件是否已经在列表中
|
|
for i in range(self.file_list.count()):
|
|
if self.file_list.item(i).data(Qt.ItemDataRole.UserRole) == file_path:
|
|
return
|
|
|
|
# 创建列表项
|
|
item = QListWidgetItem(os.path.basename(file_path))
|
|
item.setData(Qt.ItemDataRole.UserRole, file_path)
|
|
item.setToolTip(file_path)
|
|
|
|
# 添加到列表
|
|
self.file_list.addItem(item)
|
|
|
|
# 更新最近文件列表
|
|
if file_path in self.recent_files:
|
|
self.recent_files.remove(file_path)
|
|
self.recent_files.insert(0, file_path)
|
|
# 限制最近文件数量
|
|
self.recent_files = self.recent_files[:10]
|
|
self.settings.setValue("recent_files", self.recent_files)
|
|
|
|
def _add_files(self):
|
|
"""添加文件"""
|
|
files, _ = QFileDialog.getOpenFileNames(
|
|
self,
|
|
"选择文件",
|
|
os.path.expanduser("~"),
|
|
"所有文件 (*.*)"
|
|
)
|
|
|
|
if files:
|
|
for file_path in files:
|
|
self._add_file_to_list(file_path)
|
|
|
|
# 发出信号
|
|
if len(files) == 1:
|
|
self.file_selected.emit(files[0])
|
|
|
|
def _add_folder(self):
|
|
"""添加文件夹中的所有文件"""
|
|
folder = QFileDialog.getExistingDirectory(
|
|
self,
|
|
"选择文件夹",
|
|
os.path.expanduser("~")
|
|
)
|
|
|
|
if folder:
|
|
files_added = 0
|
|
for root, _, files in os.walk(folder):
|
|
for file in files:
|
|
file_path = os.path.join(root, file)
|
|
self._add_file_to_list(file_path)
|
|
files_added += 1
|
|
|
|
if files_added == 1:
|
|
self.file_selected.emit(self.file_list.item(self.file_list.count() - 1).data(Qt.ItemDataRole.UserRole))
|
|
|
|
def _clear_files(self):
|
|
"""清除文件列表"""
|
|
self.file_list.clear()
|
|
# 清除最近文件列表
|
|
self.recent_files = []
|
|
# 更新设置
|
|
self.settings.setValue("recent_files", self.recent_files)
|
|
|
|
def _on_item_double_clicked(self, item):
|
|
"""处理项目双击事件"""
|
|
file_path = item.data(Qt.ItemDataRole.UserRole)
|
|
self.file_selected.emit(file_path)
|
|
|
|
def _show_context_menu(self, position):
|
|
"""显示上下文菜单"""
|
|
menu = QMenu()
|
|
|
|
# 添加菜单项
|
|
remove_action = menu.addAction("移除")
|
|
remove_action.triggered.connect(self._remove_selected_files)
|
|
|
|
# 显示菜单
|
|
menu.exec(self.file_list.mapToGlobal(position))
|
|
|
|
def _remove_selected_files(self):
|
|
"""移除选定的文件"""
|
|
for item in self.file_list.selectedItems():
|
|
self.file_list.takeItem(self.file_list.row(item))
|
|
|
|
def get_selected_files(self):
|
|
"""获取选定的文件列表"""
|
|
files = []
|
|
|
|
# 如果有选定的项目,返回选定的文件
|
|
if self.file_list.selectedItems():
|
|
for item in self.file_list.selectedItems():
|
|
files.append(item.data(Qt.ItemDataRole.UserRole))
|
|
# 否则返回所有文件
|
|
else:
|
|
for i in range(self.file_list.count()):
|
|
files.append(self.file_list.item(i).data(Qt.ItemDataRole.UserRole))
|
|
|
|
return files
|
|
|
|
def dragEnterEvent(self, event: QDragEnterEvent):
|
|
"""处理拖动进入事件"""
|
|
if event.mimeData().hasUrls():
|
|
event.acceptProposedAction()
|
|
|
|
def dropEvent(self, event: QDropEvent):
|
|
"""处理放置事件"""
|
|
urls = event.mimeData().urls()
|
|
|
|
for url in urls:
|
|
path = url.toLocalFile()
|
|
|
|
if os.path.isfile(path):
|
|
self._add_file_to_list(path)
|
|
elif os.path.isdir(path):
|
|
for root, _, files in os.walk(path):
|
|
for file in files:
|
|
file_path = os.path.join(root, file)
|
|
self._add_file_to_list(file_path)
|
|
|
|
# 如果只添加了一个文件,发出信号
|
|
if len(urls) == 1 and os.path.isfile(urls[0].toLocalFile()):
|
|
self.file_selected.emit(urls[0].toLocalFile())
|
|
|
|
def _on_convert_clicked(self):
|
|
"""处理转换按钮点击事件"""
|
|
self.convert_clicked.emit()
|
|
|
|
def _on_batch_convert_clicked(self):
|
|
"""处理批量转换按钮点击事件"""
|
|
self.batch_convert_clicked.emit() |