""" 代码生成对话框 用于配置和生成代码 """ 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")