360 lines
13 KiB
Python
360 lines
13 KiB
Python
|
|
"""
|
||
|
|
消息编辑对话框
|
||
|
|
用于创建和编辑消息
|
||
|
|
"""
|
||
|
|
from PyQt5.QtWidgets import (
|
||
|
|
QDialog, QVBoxLayout, QHBoxLayout, QFormLayout,
|
||
|
|
QLineEdit, QComboBox, QTextEdit, QPushButton,
|
||
|
|
QLabel, QMessageBox, QGroupBox, QListWidget,
|
||
|
|
QListWidgetItem, QSplitter, QWidget
|
||
|
|
)
|
||
|
|
from PyQt5.QtCore import Qt, pyqtSignal
|
||
|
|
|
||
|
|
from models.message import Message
|
||
|
|
from models.field import Field
|
||
|
|
from config import ProtocolType, SerializationType
|
||
|
|
from controllers.field_controller import FieldController
|
||
|
|
from utils.logger import get_logger
|
||
|
|
|
||
|
|
logger = get_logger(__name__)
|
||
|
|
|
||
|
|
|
||
|
|
class MessageDialog(QDialog):
|
||
|
|
"""消息编辑对话框"""
|
||
|
|
|
||
|
|
message_saved = pyqtSignal(Message)
|
||
|
|
|
||
|
|
def __init__(self, parent=None, message: Message = None):
|
||
|
|
super().__init__(parent)
|
||
|
|
|
||
|
|
self.message = message
|
||
|
|
self.field_controller = FieldController()
|
||
|
|
self.selected_fields = []
|
||
|
|
|
||
|
|
self.init_ui()
|
||
|
|
|
||
|
|
if message:
|
||
|
|
self.load_message_data(message)
|
||
|
|
self.setWindowTitle("编辑消息")
|
||
|
|
else:
|
||
|
|
self.setWindowTitle("新建消息")
|
||
|
|
|
||
|
|
# 加载可用字段
|
||
|
|
self.load_available_fields()
|
||
|
|
|
||
|
|
def init_ui(self):
|
||
|
|
"""初始化UI"""
|
||
|
|
self.setModal(True)
|
||
|
|
self.setMinimumSize(800, 600)
|
||
|
|
|
||
|
|
# 主布局
|
||
|
|
main_layout = QVBoxLayout(self)
|
||
|
|
|
||
|
|
# 基本信息组
|
||
|
|
basic_group = QGroupBox("基本信息")
|
||
|
|
basic_layout = QFormLayout(basic_group)
|
||
|
|
|
||
|
|
# 完整名称
|
||
|
|
self.full_name_edit = QLineEdit()
|
||
|
|
self.full_name_edit.setPlaceholderText("例如: Radar.Receiver.v3")
|
||
|
|
basic_layout.addRow("完整名称*:", self.full_name_edit)
|
||
|
|
|
||
|
|
# 系统名
|
||
|
|
self.system_name_edit = QLineEdit()
|
||
|
|
self.system_name_edit.setPlaceholderText("例如: Radar")
|
||
|
|
basic_layout.addRow("系统名*:", self.system_name_edit)
|
||
|
|
|
||
|
|
# 消息类型
|
||
|
|
self.message_type_edit = QLineEdit()
|
||
|
|
self.message_type_edit.setPlaceholderText("例如: Receiver")
|
||
|
|
basic_layout.addRow("消息类型*:", self.message_type_edit)
|
||
|
|
|
||
|
|
# 版本号
|
||
|
|
self.version_edit = QLineEdit()
|
||
|
|
self.version_edit.setPlaceholderText("例如: v3")
|
||
|
|
basic_layout.addRow("版本号*:", self.version_edit)
|
||
|
|
|
||
|
|
# 协议
|
||
|
|
self.protocol_combo = QComboBox()
|
||
|
|
for protocol in ProtocolType:
|
||
|
|
self.protocol_combo.addItem(protocol.value, protocol)
|
||
|
|
basic_layout.addRow("传输协议*:", self.protocol_combo)
|
||
|
|
|
||
|
|
# 序列化
|
||
|
|
self.serialization_combo = QComboBox()
|
||
|
|
for serialization in SerializationType:
|
||
|
|
self.serialization_combo.addItem(serialization.value, serialization)
|
||
|
|
basic_layout.addRow("序列化格式*:", self.serialization_combo)
|
||
|
|
|
||
|
|
# 描述
|
||
|
|
self.description_edit = QTextEdit()
|
||
|
|
self.description_edit.setPlaceholderText("消息的详细描述...")
|
||
|
|
self.description_edit.setMaximumHeight(60)
|
||
|
|
basic_layout.addRow("描述:", self.description_edit)
|
||
|
|
|
||
|
|
main_layout.addWidget(basic_group)
|
||
|
|
|
||
|
|
# 字段选择组
|
||
|
|
field_group = QGroupBox("字段配置")
|
||
|
|
field_layout = QVBoxLayout(field_group)
|
||
|
|
|
||
|
|
# 创建分割器
|
||
|
|
splitter = QSplitter(Qt.Horizontal)
|
||
|
|
|
||
|
|
# 左侧:可用字段
|
||
|
|
left_widget = QWidget()
|
||
|
|
left_layout = QVBoxLayout(left_widget)
|
||
|
|
left_layout.setContentsMargins(0, 0, 0, 0)
|
||
|
|
|
||
|
|
left_label = QLabel("可用字段:")
|
||
|
|
left_layout.addWidget(left_label)
|
||
|
|
|
||
|
|
# 搜索框
|
||
|
|
self.field_search_edit = QLineEdit()
|
||
|
|
self.field_search_edit.setPlaceholderText("搜索字段...")
|
||
|
|
self.field_search_edit.textChanged.connect(self.filter_available_fields)
|
||
|
|
left_layout.addWidget(self.field_search_edit)
|
||
|
|
|
||
|
|
self.available_fields_list = QListWidget()
|
||
|
|
self.available_fields_list.setSelectionMode(QListWidget.ExtendedSelection)
|
||
|
|
left_layout.addWidget(self.available_fields_list)
|
||
|
|
|
||
|
|
splitter.addWidget(left_widget)
|
||
|
|
|
||
|
|
# 中间:操作按钮
|
||
|
|
middle_widget = QWidget()
|
||
|
|
middle_layout = QVBoxLayout(middle_widget)
|
||
|
|
middle_layout.setContentsMargins(5, 0, 5, 0)
|
||
|
|
middle_layout.addStretch()
|
||
|
|
|
||
|
|
self.add_field_btn = QPushButton(">>")
|
||
|
|
self.add_field_btn.setMaximumWidth(50)
|
||
|
|
self.add_field_btn.clicked.connect(self.on_add_fields)
|
||
|
|
middle_layout.addWidget(self.add_field_btn)
|
||
|
|
|
||
|
|
self.remove_field_btn = QPushButton("<<")
|
||
|
|
self.remove_field_btn.setMaximumWidth(50)
|
||
|
|
self.remove_field_btn.clicked.connect(self.on_remove_fields)
|
||
|
|
middle_layout.addWidget(self.remove_field_btn)
|
||
|
|
|
||
|
|
middle_layout.addStretch()
|
||
|
|
|
||
|
|
splitter.addWidget(middle_widget)
|
||
|
|
|
||
|
|
# 右侧:已选字段
|
||
|
|
right_widget = QWidget()
|
||
|
|
right_layout = QVBoxLayout(right_widget)
|
||
|
|
right_layout.setContentsMargins(0, 0, 0, 0)
|
||
|
|
|
||
|
|
right_label = QLabel("已选字段:")
|
||
|
|
right_layout.addWidget(right_label)
|
||
|
|
|
||
|
|
self.selected_fields_list = QListWidget()
|
||
|
|
self.selected_fields_list.setSelectionMode(QListWidget.ExtendedSelection)
|
||
|
|
right_layout.addWidget(self.selected_fields_list)
|
||
|
|
|
||
|
|
# 排序按钮
|
||
|
|
order_layout = QHBoxLayout()
|
||
|
|
self.move_up_btn = QPushButton("上移")
|
||
|
|
self.move_up_btn.clicked.connect(self.on_move_up)
|
||
|
|
self.move_down_btn = QPushButton("下移")
|
||
|
|
self.move_down_btn.clicked.connect(self.on_move_down)
|
||
|
|
order_layout.addWidget(self.move_up_btn)
|
||
|
|
order_layout.addWidget(self.move_down_btn)
|
||
|
|
order_layout.addStretch()
|
||
|
|
right_layout.addLayout(order_layout)
|
||
|
|
|
||
|
|
splitter.addWidget(right_widget)
|
||
|
|
|
||
|
|
splitter.setStretchFactor(0, 1)
|
||
|
|
splitter.setStretchFactor(1, 0)
|
||
|
|
splitter.setStretchFactor(2, 1)
|
||
|
|
|
||
|
|
field_layout.addWidget(splitter)
|
||
|
|
main_layout.addWidget(field_group)
|
||
|
|
|
||
|
|
# 提示信息
|
||
|
|
hint_label = QLabel("* 标记为必填项,消息至少需要包含一个字段")
|
||
|
|
hint_label.setStyleSheet("color: #666666; font-size: 11px;")
|
||
|
|
main_layout.addWidget(hint_label)
|
||
|
|
|
||
|
|
# 按钮
|
||
|
|
button_layout = QHBoxLayout()
|
||
|
|
|
||
|
|
self.save_btn = QPushButton("保存")
|
||
|
|
self.save_btn.clicked.connect(self.on_save)
|
||
|
|
self.save_btn.setDefault(True)
|
||
|
|
|
||
|
|
self.cancel_btn = QPushButton("取消")
|
||
|
|
self.cancel_btn.clicked.connect(self.reject)
|
||
|
|
|
||
|
|
button_layout.addStretch()
|
||
|
|
button_layout.addWidget(self.save_btn)
|
||
|
|
button_layout.addWidget(self.cancel_btn)
|
||
|
|
|
||
|
|
main_layout.addLayout(button_layout)
|
||
|
|
|
||
|
|
# 连接信号:自动生成完整名称
|
||
|
|
self.system_name_edit.textChanged.connect(self.update_full_name)
|
||
|
|
self.message_type_edit.textChanged.connect(self.update_full_name)
|
||
|
|
self.version_edit.textChanged.connect(self.update_full_name)
|
||
|
|
|
||
|
|
def update_full_name(self):
|
||
|
|
"""自动更新完整名称"""
|
||
|
|
system_name = self.system_name_edit.text().strip()
|
||
|
|
message_type = self.message_type_edit.text().strip()
|
||
|
|
version = self.version_edit.text().strip()
|
||
|
|
|
||
|
|
if system_name and message_type and version:
|
||
|
|
full_name = f"{system_name}.{message_type}.{version}"
|
||
|
|
self.full_name_edit.setText(full_name)
|
||
|
|
|
||
|
|
def load_available_fields(self):
|
||
|
|
"""加载可用字段"""
|
||
|
|
fields, _ = self.field_controller.get_all_fields(page=1, page_size=1000)
|
||
|
|
|
||
|
|
self.available_fields_list.clear()
|
||
|
|
for field in fields:
|
||
|
|
item = QListWidgetItem(f"{field.full_name} ({field.type.value})")
|
||
|
|
item.setData(Qt.UserRole, field)
|
||
|
|
self.available_fields_list.addItem(item)
|
||
|
|
|
||
|
|
def filter_available_fields(self, text: str):
|
||
|
|
"""过滤可用字段"""
|
||
|
|
for i in range(self.available_fields_list.count()):
|
||
|
|
item = self.available_fields_list.item(i)
|
||
|
|
item.setHidden(text.lower() not in item.text().lower())
|
||
|
|
|
||
|
|
def load_message_data(self, message: Message):
|
||
|
|
"""加载消息数据"""
|
||
|
|
self.full_name_edit.setText(message.full_name)
|
||
|
|
self.system_name_edit.setText(message.system_name)
|
||
|
|
self.message_type_edit.setText(message.message_type)
|
||
|
|
self.version_edit.setText(message.version)
|
||
|
|
|
||
|
|
# 设置协议
|
||
|
|
index = self.protocol_combo.findData(message.protocol)
|
||
|
|
if index >= 0:
|
||
|
|
self.protocol_combo.setCurrentIndex(index)
|
||
|
|
|
||
|
|
# 设置序列化
|
||
|
|
index = self.serialization_combo.findData(message.serialization)
|
||
|
|
if index >= 0:
|
||
|
|
self.serialization_combo.setCurrentIndex(index)
|
||
|
|
|
||
|
|
if message.description:
|
||
|
|
self.description_edit.setText(message.description)
|
||
|
|
|
||
|
|
# 加载已选字段
|
||
|
|
self.selected_fields = message.fields.copy()
|
||
|
|
for field in self.selected_fields:
|
||
|
|
item = QListWidgetItem(f"{field.full_name} ({field.type.value})")
|
||
|
|
item.setData(Qt.UserRole, field)
|
||
|
|
self.selected_fields_list.addItem(item)
|
||
|
|
|
||
|
|
def on_add_fields(self):
|
||
|
|
"""添加字段"""
|
||
|
|
selected_items = self.available_fields_list.selectedItems()
|
||
|
|
|
||
|
|
for item in selected_items:
|
||
|
|
field = item.data(Qt.UserRole)
|
||
|
|
|
||
|
|
# 检查是否已存在
|
||
|
|
if any(f.id == field.id for f in self.selected_fields):
|
||
|
|
continue
|
||
|
|
|
||
|
|
self.selected_fields.append(field)
|
||
|
|
|
||
|
|
new_item = QListWidgetItem(f"{field.full_name} ({field.type.value})")
|
||
|
|
new_item.setData(Qt.UserRole, field)
|
||
|
|
self.selected_fields_list.addItem(new_item)
|
||
|
|
|
||
|
|
def on_remove_fields(self):
|
||
|
|
"""移除字段"""
|
||
|
|
selected_items = self.selected_fields_list.selectedItems()
|
||
|
|
|
||
|
|
for item in selected_items:
|
||
|
|
field = item.data(Qt.UserRole)
|
||
|
|
|
||
|
|
# 从列表中移除
|
||
|
|
if field in self.selected_fields:
|
||
|
|
self.selected_fields.remove(field)
|
||
|
|
|
||
|
|
# 从UI中移除
|
||
|
|
row = self.selected_fields_list.row(item)
|
||
|
|
self.selected_fields_list.takeItem(row)
|
||
|
|
|
||
|
|
def on_move_up(self):
|
||
|
|
"""上移字段"""
|
||
|
|
current_row = self.selected_fields_list.currentRow()
|
||
|
|
if current_row > 0:
|
||
|
|
item = self.selected_fields_list.takeItem(current_row)
|
||
|
|
self.selected_fields_list.insertItem(current_row - 1, item)
|
||
|
|
self.selected_fields_list.setCurrentRow(current_row - 1)
|
||
|
|
|
||
|
|
# 更新字段列表
|
||
|
|
self.selected_fields[current_row], self.selected_fields[current_row - 1] = \
|
||
|
|
self.selected_fields[current_row - 1], self.selected_fields[current_row]
|
||
|
|
|
||
|
|
def on_move_down(self):
|
||
|
|
"""下移字段"""
|
||
|
|
current_row = self.selected_fields_list.currentRow()
|
||
|
|
if current_row < self.selected_fields_list.count() - 1:
|
||
|
|
item = self.selected_fields_list.takeItem(current_row)
|
||
|
|
self.selected_fields_list.insertItem(current_row + 1, item)
|
||
|
|
self.selected_fields_list.setCurrentRow(current_row + 1)
|
||
|
|
|
||
|
|
# 更新字段列表
|
||
|
|
self.selected_fields[current_row], self.selected_fields[current_row + 1] = \
|
||
|
|
self.selected_fields[current_row + 1], self.selected_fields[current_row]
|
||
|
|
|
||
|
|
def validate_input(self) -> tuple[bool, str]:
|
||
|
|
"""验证输入"""
|
||
|
|
if not self.full_name_edit.text().strip():
|
||
|
|
return False, "完整名称不能为空"
|
||
|
|
|
||
|
|
if not self.system_name_edit.text().strip():
|
||
|
|
return False, "系统名不能为空"
|
||
|
|
|
||
|
|
if not self.message_type_edit.text().strip():
|
||
|
|
return False, "消息类型不能为空"
|
||
|
|
|
||
|
|
if not self.version_edit.text().strip():
|
||
|
|
return False, "版本号不能为空"
|
||
|
|
|
||
|
|
if len(self.selected_fields) == 0:
|
||
|
|
return False, "消息至少需要包含一个字段"
|
||
|
|
|
||
|
|
return True, ""
|
||
|
|
|
||
|
|
def on_save(self):
|
||
|
|
"""保存消息"""
|
||
|
|
# 验证输入
|
||
|
|
is_valid, error_msg = self.validate_input()
|
||
|
|
if not is_valid:
|
||
|
|
QMessageBox.warning(self, "验证失败", error_msg)
|
||
|
|
return
|
||
|
|
|
||
|
|
# 构建消息对象
|
||
|
|
message_data = {
|
||
|
|
'full_name': self.full_name_edit.text().strip(),
|
||
|
|
'system_name': self.system_name_edit.text().strip(),
|
||
|
|
'message_type': self.message_type_edit.text().strip(),
|
||
|
|
'version': self.version_edit.text().strip(),
|
||
|
|
'protocol': self.protocol_combo.currentData().value,
|
||
|
|
'serialization': self.serialization_combo.currentData().value,
|
||
|
|
'description': self.description_edit.toPlainText().strip() or None,
|
||
|
|
'fields': [f.to_dict() for f in self.selected_fields],
|
||
|
|
}
|
||
|
|
|
||
|
|
if self.message:
|
||
|
|
message_data['id'] = self.message.id
|
||
|
|
|
||
|
|
try:
|
||
|
|
message = Message.from_dict(message_data)
|
||
|
|
self.message_saved.emit(message)
|
||
|
|
self.accept()
|
||
|
|
except Exception as e:
|
||
|
|
QMessageBox.critical(self, "错误", f"创建消息对象失败: {str(e)}")
|
||
|
|
logger.error(f"Failed to create message object: {e}")
|