411 lines
15 KiB
Python
411 lines
15 KiB
Python
|
||
import os
|
||
import re
|
||
from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout,
|
||
QLineEdit, QPushButton, QLabel,
|
||
QTreeView, QTreeWidget, QTreeWidgetItem, QWidget,
|
||
QFileDialog, QMessageBox, QAbstractItemView, QMenu, QDockWidget, QButtonGroup, QToolButton, QFrame, QSizePolicy)
|
||
from PyQt5.QtCore import Qt, QUrl, QMimeData, QPoint, QSize
|
||
from PyQt5.QtGui import QDrag, QPainter, QPixmap, QPen, QBrush, QFont
|
||
from PyQt5.sip import wrapinstance
|
||
from ui.icon_manager import IconManager
|
||
|
||
class UniversalMessageDialog(QDialog):
|
||
"""通用消息对话框类 - 支持不同图标和按钮配置"""
|
||
|
||
# 消息类型枚举
|
||
SUCCESS = "success_icon"
|
||
WARNING = "warning_icon"
|
||
ERROR = "fail_icon"
|
||
INFO = "info"
|
||
|
||
def __init__(self, parent, title, message, message_type=INFO, show_cancel=True,
|
||
confirm_text="确认", cancel_text="取消", icon_size=QSize(20, 20)):
|
||
"""
|
||
初始化通用消息对话框
|
||
|
||
Args:
|
||
parent: 父窗口
|
||
title: 对话框标题
|
||
message: 消息内容
|
||
message_type: 消息类型 (SUCCESS, WARNING, ERROR, INFO)
|
||
show_cancel: 是否显示取消按钮
|
||
confirm_text: 确认按钮文字
|
||
cancel_text: 取消按钮文字
|
||
icon_size: 图标尺寸
|
||
"""
|
||
super().__init__(parent)
|
||
self.setWindowTitle(title)
|
||
self.setObjectName("universalMessageDialog")
|
||
self.setModal(True)
|
||
self.resize(508, 134)
|
||
self.setMinimumSize(508, 134)
|
||
self.setWindowFlags(Qt.Dialog | Qt.FramelessWindowHint)
|
||
self.setAttribute(Qt.WA_TranslucentBackground, True)
|
||
|
||
# 对话框配置
|
||
self.message_type = message_type
|
||
self.show_cancel = show_cancel
|
||
self.confirm_text = confirm_text
|
||
self.cancel_text = cancel_text
|
||
self.icon_size = icon_size
|
||
|
||
# 拖拽相关
|
||
self.dragging = False
|
||
self.drag_position = QPoint()
|
||
|
||
# 图标管理
|
||
self.icon_manager = IconManager()
|
||
self._title_icon_size = QSize(18, 18)
|
||
self._icon_close = self.icon_manager.get_icon('close_bt_icon', self._title_icon_size)
|
||
|
||
# 根据消息类型获取对应图标
|
||
self._message_icon = self._get_message_icon()
|
||
|
||
# 设置样式
|
||
self._setup_styles()
|
||
|
||
# 创建UI
|
||
self._create_ui(message)
|
||
|
||
def _get_message_icon(self):
|
||
"""根据消息类型获取对应图标"""
|
||
icon_map = {
|
||
self.SUCCESS: 'success_icon',
|
||
self.WARNING: 'warning_icon',
|
||
self.ERROR: 'fail_icon',
|
||
self.INFO: 'success_icon' # 默认使用成功图标
|
||
}
|
||
|
||
icon_name = icon_map.get(self.message_type, 'success_icon')
|
||
return self.icon_manager.get_icon(icon_name, self.icon_size)
|
||
|
||
def _setup_styles(self):
|
||
"""设置对话框样式"""
|
||
self.setStyleSheet("""
|
||
QDialog#universalMessageDialog {
|
||
background-color: transparent;
|
||
border: none;
|
||
}
|
||
QFrame#baseFrame {
|
||
background-color: #19191B;
|
||
border: 1px solid #3E3E42;
|
||
border-radius: 5px;
|
||
}
|
||
QWidget#titleBar {
|
||
background-color: transparent;
|
||
border: none;
|
||
border-radius: 5px 5px 0px 0px;
|
||
min-height: 32px;
|
||
max-height: 32px;
|
||
}
|
||
QWidget#titleBar QWidget {
|
||
background-color: transparent;
|
||
border: none;
|
||
}
|
||
QLabel#titleLabel {
|
||
color: #FFFFFF;
|
||
font-family: 'Inter', 'Microsoft YaHei', sans-serif;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
letter-spacing: 0.7px;
|
||
}
|
||
QWidget#controlButtons QPushButton {
|
||
background-color: transparent;
|
||
border: none;
|
||
color: #EBEBEB;
|
||
font-size: 14px;
|
||
min-width: 18px;
|
||
max-width: 18px;
|
||
min-height: 18px;
|
||
max-height: 18px;
|
||
padding: 0px;
|
||
border-radius: 3px;
|
||
}
|
||
QWidget#controlButtons QPushButton:hover {
|
||
background-color: #2A2D2E;
|
||
color: #FFFFFF;
|
||
}
|
||
QPushButton#closeButton {
|
||
border-radius: 0px 5px 0px 0px;
|
||
}
|
||
QPushButton#closeButton:hover {
|
||
background-color: #2A2D2E;
|
||
color: #FFFFFF;
|
||
}
|
||
QFrame#titleSeparator {
|
||
background-color: #3E3E42;
|
||
border: none;
|
||
min-height: 1px;
|
||
max-height: 1px;
|
||
}
|
||
QWidget#contentWidget {
|
||
background-color: transparent;
|
||
border: none;
|
||
}
|
||
QLabel#iconLabel {
|
||
background-color: transparent;
|
||
}
|
||
QLabel#messageLabel {
|
||
background-color: transparent;
|
||
color: #EBEBEB;
|
||
font-family: 'Inter', 'Microsoft YaHei', sans-serif;
|
||
font-size: 13px;
|
||
font-weight: 400;
|
||
letter-spacing: 0.6px;
|
||
line-height: 1.4;
|
||
padding: 0px;
|
||
margin: 0px;
|
||
}
|
||
QWidget#buttonWidget {
|
||
background-color: transparent;
|
||
}
|
||
QPushButton {
|
||
background-color: rgba(89, 98, 118, 0.5);
|
||
color: #EBEBEB;
|
||
border: none;
|
||
border-radius: 2px;
|
||
padding: 0px 12px;
|
||
font-family: 'Inter', 'Microsoft YaHei', sans-serif;
|
||
font-weight: 300;
|
||
font-size: 10px;
|
||
letter-spacing: 0.5px;
|
||
min-width: 90px;
|
||
max-width: 90px;
|
||
min-height: 28px;
|
||
max-height: 28px;
|
||
}
|
||
QPushButton:hover {
|
||
background-color: #3067C0;
|
||
color: #FFFFFF;
|
||
}
|
||
QPushButton:pressed {
|
||
background-color: #2556A0;
|
||
color: #FFFFFF;
|
||
}
|
||
QPushButton#primaryButton {
|
||
background-color: rgba(89, 98, 118, 0.5);
|
||
border: none;
|
||
color: #EBEBEB;
|
||
font-weight: 300;
|
||
}
|
||
QPushButton#primaryButton:hover {
|
||
background-color: #2556A0;
|
||
}
|
||
QPushButton#primaryButton:pressed {
|
||
background-color: #1E4A8C;
|
||
}
|
||
QPushButton#secondaryButton {
|
||
background-color: rgba(89, 98, 118, 0.5);
|
||
border: none;
|
||
color: #EBEBEB;
|
||
}
|
||
QPushButton#secondaryButton:hover {
|
||
background-color: #3067C0;
|
||
color: #FFFFFF;
|
||
}
|
||
QPushButton#secondaryButton:pressed {
|
||
background-color: #2556A0;
|
||
color: #FFFFFF;
|
||
}
|
||
""")
|
||
|
||
def _create_ui(self, message):
|
||
"""构建用户界面"""
|
||
main_layout = QVBoxLayout(self)
|
||
main_layout.setContentsMargins(0, 0, 0, 0)
|
||
main_layout.setSpacing(0)
|
||
|
||
base_frame = QFrame()
|
||
base_frame.setObjectName('baseFrame')
|
||
base_frame.setFrameShape(QFrame.NoFrame)
|
||
base_frame.setAttribute(Qt.WA_StyledBackground, True)
|
||
|
||
base_layout = QVBoxLayout(base_frame)
|
||
base_layout.setContentsMargins(25, 14, 25, 14)
|
||
base_layout.setSpacing(0)
|
||
|
||
self._create_title_bar()
|
||
base_layout.addWidget(self.title_bar)
|
||
base_layout.addSpacing(4)
|
||
|
||
title_separator = QFrame()
|
||
title_separator.setObjectName('titleSeparator')
|
||
title_separator.setFrameShape(QFrame.HLine)
|
||
title_separator.setFrameShadow(QFrame.Plain)
|
||
base_layout.addWidget(title_separator)
|
||
base_layout.addSpacing(10)
|
||
|
||
content_widget = QWidget()
|
||
content_widget.setObjectName('contentWidget')
|
||
content_layout = QVBoxLayout(content_widget)
|
||
content_layout.setContentsMargins(0, 0, 0, 0)
|
||
content_layout.setSpacing(10)
|
||
|
||
message_area = QHBoxLayout()
|
||
message_area.setContentsMargins(0, 0, 0, 0)
|
||
message_area.setSpacing(10)
|
||
|
||
# 用一个垂直布局包裹icon_label,确保顶部对齐
|
||
icon_vbox = QVBoxLayout()
|
||
icon_vbox.setContentsMargins(0, 0, 0, 0)
|
||
icon_vbox.setSpacing(0)
|
||
icon_label = QLabel()
|
||
icon_label.setObjectName('iconLabel')
|
||
if self._message_icon and not self._message_icon.isNull():
|
||
icon_label.setPixmap(self._message_icon.pixmap(self.icon_size))
|
||
icon_label.setAlignment(Qt.AlignTop | Qt.AlignLeft)
|
||
icon_label.setFixedSize(self.icon_size)
|
||
icon_vbox.addWidget(icon_label, alignment=Qt.AlignTop)
|
||
icon_vbox.addStretch()
|
||
message_area.addLayout(icon_vbox)
|
||
|
||
self.message_label = QLabel(message)
|
||
self.message_label.setObjectName('messageLabel')
|
||
self.message_label.setWordWrap(True)
|
||
self.message_label.setAlignment(Qt.AlignTop | Qt.AlignLeft)
|
||
self.message_label.setMinimumHeight(self.icon_size.height())
|
||
self.message_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||
message_area.addWidget(self.message_label, 1)
|
||
message_area.addStretch()
|
||
|
||
content_layout.addLayout(message_area)
|
||
base_layout.addWidget(content_widget)
|
||
base_layout.addSpacing(10)
|
||
|
||
button_widget = QWidget()
|
||
button_widget.setObjectName('buttonWidget')
|
||
button_layout = QHBoxLayout(button_widget)
|
||
button_layout.setContentsMargins(0, 0, 0, 0)
|
||
button_layout.setSpacing(10)
|
||
button_layout.addStretch()
|
||
|
||
if self.show_cancel:
|
||
self.cancel_button = QPushButton(self.cancel_text)
|
||
self.cancel_button.setObjectName("secondaryButton")
|
||
self.cancel_button.clicked.connect(self.reject)
|
||
self.cancel_button.setFixedSize(90, 28)
|
||
button_layout.addWidget(self.cancel_button)
|
||
|
||
self.confirm_button = QPushButton(self.confirm_text)
|
||
self.confirm_button.setObjectName("primaryButton")
|
||
self.confirm_button.clicked.connect(self.accept)
|
||
self.confirm_button.setFixedSize(90, 28)
|
||
button_layout.addWidget(self.confirm_button)
|
||
|
||
self.confirm_button.setDefault(True)
|
||
self.confirm_button.setAutoDefault(True)
|
||
if self.show_cancel:
|
||
self.cancel_button.setAutoDefault(False)
|
||
|
||
base_layout.addWidget(button_widget)
|
||
|
||
main_layout.addWidget(base_frame)
|
||
|
||
def _create_title_bar(self):
|
||
"""创建自定义标题栏"""
|
||
self.title_bar = QFrame()
|
||
self.title_bar.setObjectName("titleBar")
|
||
|
||
title_layout = QHBoxLayout(self.title_bar)
|
||
title_layout.setContentsMargins(0, 0, 0, 0)
|
||
title_layout.setSpacing(0)
|
||
|
||
self.title_label = QLabel(self.windowTitle())
|
||
self.title_label.setObjectName("titleLabel")
|
||
self.title_label.setAlignment(Qt.AlignVCenter | Qt.AlignLeft)
|
||
title_layout.addWidget(self.title_label, 1)
|
||
|
||
title_layout.addStretch()
|
||
|
||
controls = QWidget()
|
||
controls.setObjectName("controlButtons")
|
||
controls_layout = QHBoxLayout(controls)
|
||
controls_layout.setContentsMargins(0, 0, 0, 0)
|
||
controls_layout.setSpacing(0)
|
||
|
||
self.close_button = QPushButton()
|
||
self.close_button.setObjectName("closeButton")
|
||
self.close_button.clicked.connect(self.reject)
|
||
self.close_button.setFocusPolicy(Qt.NoFocus)
|
||
controls_layout.addWidget(self.close_button)
|
||
|
||
self._apply_title_bar_icons()
|
||
|
||
title_layout.addWidget(controls)
|
||
|
||
|
||
def _apply_title_bar_icons(self):
|
||
"""应用标题栏图标"""
|
||
if self._icon_close:
|
||
self.close_button.setIcon(self._icon_close)
|
||
self.close_button.setIconSize(self._title_icon_size)
|
||
self.close_button.setText("")
|
||
self.close_button.setToolTip("关闭")
|
||
|
||
def setWindowTitle(self, title):
|
||
"""设置窗口标题"""
|
||
super().setWindowTitle(title)
|
||
if hasattr(self, "title_label"):
|
||
self.title_label.setText(title)
|
||
|
||
def mousePressEvent(self, event):
|
||
"""鼠标按下事件 - 用于拖拽窗口"""
|
||
if event.button() == Qt.LeftButton and self.title_bar.geometry().contains(event.pos()):
|
||
self.dragging = True
|
||
self.drag_position = event.globalPos() - self.frameGeometry().topLeft()
|
||
event.accept()
|
||
super().mousePressEvent(event)
|
||
|
||
def mouseMoveEvent(self, event):
|
||
"""鼠标移动事件 - 用于拖拽窗口"""
|
||
if event.buttons() == Qt.LeftButton and self.dragging:
|
||
self.move(event.globalPos() - self.drag_position)
|
||
event.accept()
|
||
super().mouseMoveEvent(event)
|
||
|
||
def mouseReleaseEvent(self, event):
|
||
"""鼠标释放事件 - 停止拖拽"""
|
||
if event.button() == Qt.LeftButton:
|
||
self.dragging = False
|
||
super().mouseReleaseEvent(event)
|
||
|
||
@staticmethod
|
||
def show_success(parent, title, message, show_cancel=False, confirm_text="确认"):
|
||
"""显示成功消息对话框"""
|
||
dialog = UniversalMessageDialog(
|
||
parent, title, message,
|
||
UniversalMessageDialog.SUCCESS,
|
||
show_cancel, confirm_text
|
||
)
|
||
return dialog.exec_()
|
||
|
||
@staticmethod
|
||
def show_warning(parent, title, message, show_cancel=True, confirm_text="确认", cancel_text="取消"):
|
||
"""显示警告消息对话框"""
|
||
dialog = UniversalMessageDialog(
|
||
parent, title, message,
|
||
UniversalMessageDialog.WARNING,
|
||
show_cancel, confirm_text, cancel_text
|
||
)
|
||
return dialog.exec_()
|
||
|
||
@staticmethod
|
||
def show_error(parent, title, message, show_cancel=False, confirm_text="确认"):
|
||
"""显示错误消息对话框"""
|
||
dialog = UniversalMessageDialog(
|
||
parent, title, message,
|
||
UniversalMessageDialog.ERROR,
|
||
show_cancel, confirm_text
|
||
)
|
||
return dialog.exec_()
|
||
|
||
@staticmethod
|
||
def show_info(parent, title, message, show_cancel=True, confirm_text="确认", cancel_text="取消"):
|
||
"""显示信息消息对话框"""
|
||
dialog = UniversalMessageDialog(
|
||
parent, title, message,
|
||
UniversalMessageDialog.INFO,
|
||
show_cancel, confirm_text, cancel_text
|
||
)
|
||
return dialog.exec_() |