249 lines
8.2 KiB
Python
249 lines
8.2 KiB
Python
"""
|
|
代码生成对话框
|
|
用于配置和生成代码
|
|
"""
|
|
from PyQt5.QtWidgets import (
|
|
QDialog, QVBoxLayout, QHBoxLayout, QFormLayout,
|
|
QLineEdit, QComboBox, QPushButton, QLabel,
|
|
QMessageBox, QGroupBox, QFileDialog, QTabWidget,
|
|
QTextEdit, QCheckBox
|
|
)
|
|
from PyQt5.QtCore import Qt, pyqtSignal
|
|
from pathlib import Path
|
|
|
|
from models.message import Message
|
|
from config import ProtocolType, SerializationType, LanguageStandard
|
|
from controllers.codegen_controller import CodeGenController
|
|
from ui.widgets.code_editor_widget import CodeEditorWidget
|
|
from utils.logger import get_logger
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
|
|
class CodeGenDialog(QDialog):
|
|
"""代码生成对话框"""
|
|
|
|
code_generated = pyqtSignal(dict) # 生成的代码文件字典
|
|
|
|
def __init__(self, parent=None, source_message: Message = None,
|
|
target_message: Message = None):
|
|
super().__init__(parent)
|
|
|
|
self.source_message = source_message
|
|
self.target_message = target_message
|
|
self.codegen_controller = CodeGenController()
|
|
self.generated_files = {}
|
|
|
|
self.init_ui()
|
|
self.setWindowTitle("代码生成")
|
|
|
|
def init_ui(self):
|
|
"""初始化UI"""
|
|
self.setModal(True)
|
|
self.setMinimumSize(900, 700)
|
|
|
|
# 主布局
|
|
main_layout = QVBoxLayout(self)
|
|
|
|
# 配置组
|
|
config_group = QGroupBox("生成配置")
|
|
config_layout = QFormLayout(config_group)
|
|
|
|
# 源消息
|
|
self.source_message_label = QLabel(
|
|
self.source_message.full_name if self.source_message else "未选择"
|
|
)
|
|
config_layout.addRow("源消息:", self.source_message_label)
|
|
|
|
# 目标消息
|
|
self.target_message_label = QLabel(
|
|
self.target_message.full_name if self.target_message else "未选择"
|
|
)
|
|
config_layout.addRow("目标消息:", self.target_message_label)
|
|
|
|
# 传输协议
|
|
self.protocol_combo = QComboBox()
|
|
for protocol in ProtocolType:
|
|
self.protocol_combo.addItem(protocol.value, protocol)
|
|
config_layout.addRow("传输协议*:", self.protocol_combo)
|
|
|
|
# 序列化格式
|
|
self.serialization_combo = QComboBox()
|
|
for serialization in SerializationType:
|
|
self.serialization_combo.addItem(serialization.value, serialization)
|
|
config_layout.addRow("序列化格式*:", self.serialization_combo)
|
|
|
|
# 语言标准
|
|
self.language_standard_combo = QComboBox()
|
|
for standard in LanguageStandard:
|
|
self.language_standard_combo.addItem(standard.value, standard)
|
|
self.language_standard_combo.setCurrentText("C++17")
|
|
config_layout.addRow("语言标准:", self.language_standard_combo)
|
|
|
|
# 输出目录
|
|
output_layout = QHBoxLayout()
|
|
self.output_dir_edit = QLineEdit()
|
|
self.output_dir_edit.setPlaceholderText("选择输出目录...")
|
|
self.browse_btn = QPushButton("浏览...")
|
|
self.browse_btn.clicked.connect(self.on_browse_output_dir)
|
|
output_layout.addWidget(self.output_dir_edit)
|
|
output_layout.addWidget(self.browse_btn)
|
|
config_layout.addRow("输出目录:", output_layout)
|
|
|
|
# 选项
|
|
self.include_test_checkbox = QCheckBox("生成测试代码")
|
|
config_layout.addRow("选项:", self.include_test_checkbox)
|
|
|
|
main_layout.addWidget(config_group)
|
|
|
|
# 生成按钮
|
|
gen_btn_layout = QHBoxLayout()
|
|
|
|
self.preview_btn = QPushButton("预览代码")
|
|
self.preview_btn.clicked.connect(self.on_preview)
|
|
|
|
self.generate_btn = QPushButton("生成并保存")
|
|
self.generate_btn.clicked.connect(self.on_generate)
|
|
|
|
gen_btn_layout.addWidget(self.preview_btn)
|
|
gen_btn_layout.addWidget(self.generate_btn)
|
|
gen_btn_layout.addStretch()
|
|
|
|
main_layout.addLayout(gen_btn_layout)
|
|
|
|
# 代码预览标签页
|
|
self.preview_tabs = QTabWidget()
|
|
main_layout.addWidget(self.preview_tabs)
|
|
|
|
# 底部按钮
|
|
button_layout = QHBoxLayout()
|
|
|
|
self.close_btn = QPushButton("关闭")
|
|
self.close_btn.clicked.connect(self.accept)
|
|
|
|
button_layout.addStretch()
|
|
button_layout.addWidget(self.close_btn)
|
|
|
|
main_layout.addLayout(button_layout)
|
|
|
|
def on_browse_output_dir(self):
|
|
"""浏览输出目录"""
|
|
dir_path = QFileDialog.getExistingDirectory(
|
|
self,
|
|
"选择输出目录",
|
|
"",
|
|
QFileDialog.ShowDirsOnly
|
|
)
|
|
|
|
if dir_path:
|
|
self.output_dir_edit.setText(dir_path)
|
|
|
|
def validate_config(self) -> tuple[bool, str]:
|
|
"""验证配置"""
|
|
if not self.source_message:
|
|
return False, "请先选择源消息"
|
|
|
|
if not self.target_message:
|
|
return False, "请先选择目标消息"
|
|
|
|
return True, ""
|
|
|
|
def build_config(self, include_output_dir: bool = True) -> dict:
|
|
"""构建配置字典"""
|
|
config = {
|
|
'source_message': self.source_message,
|
|
'target_message': self.target_message,
|
|
'protocol': self.protocol_combo.currentData().value,
|
|
'serialization': self.serialization_combo.currentData().value,
|
|
'language_standard': self.language_standard_combo.currentData().value,
|
|
}
|
|
|
|
if include_output_dir and self.output_dir_edit.text().strip():
|
|
config['output_dir'] = self.output_dir_edit.text().strip()
|
|
|
|
return config
|
|
|
|
def on_preview(self):
|
|
"""预览代码"""
|
|
# 验证配置
|
|
is_valid, error_msg = self.validate_config()
|
|
if not is_valid:
|
|
QMessageBox.warning(self, "验证失败", error_msg)
|
|
return
|
|
|
|
# 生成代码(不保存到文件)
|
|
config = self.build_config(include_output_dir=False)
|
|
|
|
try:
|
|
success, msg, files = self.codegen_controller.preview_code(config)
|
|
|
|
if success:
|
|
self.generated_files = files
|
|
self.display_preview(files)
|
|
QMessageBox.information(self, "成功", f"代码预览生成成功\n生成了 {len(files)} 个文件")
|
|
else:
|
|
QMessageBox.warning(self, "失败", msg)
|
|
|
|
except Exception as e:
|
|
QMessageBox.critical(self, "错误", f"代码生成失败: {str(e)}")
|
|
logger.error(f"Code generation failed: {e}")
|
|
|
|
def on_generate(self):
|
|
"""生成并保存代码"""
|
|
# 验证配置
|
|
is_valid, error_msg = self.validate_config()
|
|
if not is_valid:
|
|
QMessageBox.warning(self, "验证失败", error_msg)
|
|
return
|
|
|
|
# 检查输出目录
|
|
if not self.output_dir_edit.text().strip():
|
|
QMessageBox.warning(self, "警告", "请选择输出目录")
|
|
return
|
|
|
|
# 生成代码
|
|
config = self.build_config(include_output_dir=True)
|
|
|
|
try:
|
|
success, msg, files = self.codegen_controller.generate_code(config)
|
|
|
|
if success:
|
|
self.generated_files = files
|
|
self.display_preview(files)
|
|
self.code_generated.emit(files)
|
|
|
|
QMessageBox.information(
|
|
self,
|
|
"成功",
|
|
f"代码生成成功!\n"
|
|
f"生成了 {len(files)} 个文件\n"
|
|
f"保存位置: {self.output_dir_edit.text()}"
|
|
)
|
|
else:
|
|
QMessageBox.warning(self, "失败", msg)
|
|
|
|
except Exception as e:
|
|
QMessageBox.critical(self, "错误", f"代码生成失败: {str(e)}")
|
|
logger.error(f"Code generation failed: {e}")
|
|
|
|
def display_preview(self, files: dict):
|
|
"""显示代码预览"""
|
|
# 清空现有标签页
|
|
self.preview_tabs.clear()
|
|
|
|
# 为每个文件创建标签页
|
|
for filename, content in files.items():
|
|
# 创建代码编辑器
|
|
if filename.endswith(('.h', '.hpp', '.cpp', '.c')):
|
|
editor = CodeEditorWidget('cpp')
|
|
else:
|
|
editor = QTextEdit()
|
|
|
|
editor.setPlainText(content)
|
|
editor.setReadOnly(True)
|
|
|
|
# 添加标签页
|
|
self.preview_tabs.addTab(editor, filename)
|
|
|
|
logger.info(f"Displayed preview for {len(files)} files")
|