statable 3.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- codegen/__init__.py +38 -0
- codegen/c_code_generator.py +1752 -0
- codegen/code_merger.py +371 -0
- codegen/code_templates.py +509 -0
- codegen/config.py +167 -0
- codegen/enum_generator.py +377 -0
- codegen/event_queue_generator.py +303 -0
- codegen/interrupt_generator.py +345 -0
- codegen/naming_convention.py +171 -0
- codegen/osal_generator.py +282 -0
- codegen/role_function_generator.py +1244 -0
- codegen/sample_data.py +269 -0
- codegen/state_actions_generator.py +395 -0
- codegen/struct_generator.py +721 -0
- codegen/timer_generator.py +299 -0
- codegen/transition_generator.py +907 -0
- codegen/type_mapper.py +69 -0
- codegen/validate/__init__.py +38 -0
- codegen/validate/change_actions.py +90 -0
- codegen/validate/change_applier.py +416 -0
- codegen/validate/clipboard_manager.py +47 -0
- codegen/validate/data/__init__.py +30 -0
- codegen/validate/data/action_definitions.py +200 -0
- codegen/validate/data/keywords.py +46 -0
- codegen/validate/data/prompt_templates.py +176 -0
- codegen/validate/data/validation_rules.py +205 -0
- codegen/validate/items/__init__.py +30 -0
- codegen/validate/items/base_validator.py +25 -0
- codegen/validate/items/cell_validator.py +275 -0
- codegen/validate/items/custom_type_validator.py +75 -0
- codegen/validate/items/event_validator.py +78 -0
- codegen/validate/items/flag_validator.py +74 -0
- codegen/validate/items/interrupt_validator.py +75 -0
- codegen/validate/items/queue_validator.py +73 -0
- codegen/validate/items/role_function_validator.py +175 -0
- codegen/validate/items/state_validator.py +88 -0
- codegen/validate/items/timer_validator.py +120 -0
- codegen/validate/items/transition_validator.py +113 -0
- codegen/validate/items/variable_validator.py +132 -0
- codegen/validate/logger.py +52 -0
- codegen/validate/models.py +177 -0
- codegen/validate/prompt_generator.py +724 -0
- codegen/validate/response_parser.py +154 -0
- codegen/validate/response_validator.py +275 -0
- codegen/validate/validation_dialog.py +322 -0
- codegen/validate/validator.py +94 -0
- codegen/variable_generator.py +419 -0
- statable/__init__.py +71 -0
- statable/__main__.py +49 -0
- statable/cli.py +251 -0
- statable/global_defs.py +256 -0
- statable/mermaid_gen.py +144 -0
- statable/model.py +426 -0
- statable/parser.py +64 -0
- statable/sample_data.py +435 -0
- statable/shared/__init__.py +24 -0
- statable/shared/condition_library.py +63 -0
- statable/shared/literal_library.py +66 -0
- statable/shared/role_function_library.py +150 -0
- statable/state_machine.py +121 -0
- statable/xml_io.py +1164 -0
- statable-3.1.0.dist-info/METADATA +151 -0
- statable-3.1.0.dist-info/RECORD +117 -0
- statable-3.1.0.dist-info/WHEEL +5 -0
- statable-3.1.0.dist-info/entry_points.txt +2 -0
- statable-3.1.0.dist-info/top_level.txt +3 -0
- statable_gui/__init__.py +23 -0
- statable_gui/action_edit_dialog.py +214 -0
- statable_gui/code_generation_dialog.py +486 -0
- statable_gui/code_generation_settings_dialog.py +522 -0
- statable_gui/common_widgets.py +537 -0
- statable_gui/condition_builder_dialog.py +500 -0
- statable_gui/condition_edit_dialog.py +123 -0
- statable_gui/condition_template_dialog.py +58 -0
- statable_gui/config.py +21 -0
- statable_gui/dialogs.py +439 -0
- statable_gui/event_definition_dialog.py +605 -0
- statable_gui/event_delivery_settings_dialog.py +191 -0
- statable_gui/event_queue_dialog.py +245 -0
- statable_gui/global_defs.py +167 -0
- statable_gui/global_defs_dialog.py +796 -0
- statable_gui/i18n/__init__.py +118 -0
- statable_gui/interrupt_handler_edit_dialog.py +810 -0
- statable_gui/layer_settings_dialog.py +180 -0
- statable_gui/libcntrl/__init__.py +23 -0
- statable_gui/libcntrl/condition_library.py +13 -0
- statable_gui/libcntrl/literal_library.py +13 -0
- statable_gui/libcntrl/literal_management_dialog.py +185 -0
- statable_gui/libcntrl/role_function_edit_dialog.py +145 -0
- statable_gui/libcntrl/role_function_library.py +13 -0
- statable_gui/literal_definition_dialog.py +62 -0
- statable_gui/logger.py +83 -0
- statable_gui/main_window.py +1380 -0
- statable_gui/matrix_table.py +413 -0
- statable_gui/preference_keys.py +18 -0
- statable_gui/preferences.py +74 -0
- statable_gui/role_function_dialog.py +244 -0
- statable_gui/sample_data.py +11 -0
- statable_gui/state_actions_dialog.py +398 -0
- statable_gui/symbol_picker.py +170 -0
- statable_gui/traceball.py +37 -0
- statable_gui/transition_editor_direct/__init__.py +15 -0
- statable_gui/transition_editor_direct/actions_tab.py +856 -0
- statable_gui/transition_editor_direct/code_widget.py +344 -0
- statable_gui/transition_editor_direct/coverage_analyzer.py +163 -0
- statable_gui/transition_editor_direct/dialog.py +335 -0
- statable_gui/transition_editor_direct/draft.py +270 -0
- statable_gui/transition_editor_direct/edit_dialogs.py +160 -0
- statable_gui/transition_editor_direct/overview_tab.py +173 -0
- statable_gui/transition_editor_direct/palette_widget.py +233 -0
- statable_gui/transition_editor_direct/relations_edit_dialog.py +156 -0
- statable_gui/transition_editor_direct/relations_tab.py +230 -0
- statable_gui/transition_editor_direct/system_global_dialog.py +52 -0
- statable_gui/transition_editor_direct/transition_actions_dialog.py +109 -0
- statable_gui/transition_editor_direct/transitions_tab.py +620 -0
- statable_gui/validation_dialog.py +285 -0
- statable_gui/widgets.py +1315 -0
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
# statable_gui/code_generation_settings_dialog.py
|
|
2
|
+
"""\nCode generation settings dialog\n- Tab structure: basic settings, log settings, external include, output settings\n- Generation style / table style are fixed (table-driven + array style only)\n"""
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
import logging
|
|
7
|
+
from typing import Dict, Optional, List
|
|
8
|
+
|
|
9
|
+
from PySide6.QtWidgets import (
|
|
10
|
+
QDialog, QVBoxLayout, QHBoxLayout, QPushButton,
|
|
11
|
+
QLabel, QComboBox, QGroupBox, QFormLayout,
|
|
12
|
+
QCheckBox, QLineEdit, QFileDialog, QTabWidget,
|
|
13
|
+
QWidget, QMessageBox, QDialogButtonBox, QListWidget,
|
|
14
|
+
QListWidgetItem, QSpinBox, QAbstractItemView
|
|
15
|
+
)
|
|
16
|
+
from PySide6.QtCore import Qt
|
|
17
|
+
|
|
18
|
+
# Path settings
|
|
19
|
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
from codegen.config import CodeGenerationConfig, ConfigManager
|
|
23
|
+
except ImportError:
|
|
24
|
+
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'codegen'))
|
|
25
|
+
from config import CodeGenerationConfig, ConfigManager
|
|
26
|
+
|
|
27
|
+
logger = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class CodeGenerationSettingsDialog(QDialog):
|
|
31
|
+
"""Code generation settings dialog"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, config_manager: Optional[ConfigManager] = None, parent=None):
|
|
34
|
+
super().__init__(parent)
|
|
35
|
+
self.config_manager = config_manager or ConfigManager()
|
|
36
|
+
self.config = self.config_manager.get_config()
|
|
37
|
+
|
|
38
|
+
self.setWindowTitle(self.tr("Code generation settings"))
|
|
39
|
+
self.setMinimumSize(600, 600)
|
|
40
|
+
|
|
41
|
+
self._setup_ui()
|
|
42
|
+
self._load_config()
|
|
43
|
+
|
|
44
|
+
def _setup_ui(self):
|
|
45
|
+
"""Build UI"""
|
|
46
|
+
main_layout = QVBoxLayout(self)
|
|
47
|
+
|
|
48
|
+
# Tab widget
|
|
49
|
+
self.tab_widget = QTabWidget()
|
|
50
|
+
main_layout.addWidget(self.tab_widget)
|
|
51
|
+
|
|
52
|
+
# Tab
|
|
53
|
+
self.basic_tab = QWidget()
|
|
54
|
+
self._setup_basic_tab()
|
|
55
|
+
self.tab_widget.addTab(self.basic_tab, self.tr("Basic settings"))
|
|
56
|
+
|
|
57
|
+
# Log settings tab
|
|
58
|
+
self.log_tab = QWidget()
|
|
59
|
+
self._setup_log_tab()
|
|
60
|
+
self.tab_widget.addTab(self.log_tab, self.tr("Log settings"))
|
|
61
|
+
|
|
62
|
+
# Output settings tab
|
|
63
|
+
self.include_tab = QWidget()
|
|
64
|
+
self._setup_include_tab()
|
|
65
|
+
self.tab_widget.addTab(self.include_tab, self.tr("External include"))
|
|
66
|
+
|
|
67
|
+
self.output_tab = QWidget()
|
|
68
|
+
self._setup_output_tab()
|
|
69
|
+
self.tab_widget.addTab(self.output_tab, self.tr("Output settings"))
|
|
70
|
+
|
|
71
|
+
# Buttons
|
|
72
|
+
button_layout = QHBoxLayout()
|
|
73
|
+
button_layout.addStretch()
|
|
74
|
+
|
|
75
|
+
self.reset_btn = QPushButton(self.tr("Reset"))
|
|
76
|
+
self.reset_btn.clicked.connect(self._on_reset)
|
|
77
|
+
button_layout.addWidget(self.reset_btn)
|
|
78
|
+
|
|
79
|
+
self.cancel_btn = QPushButton(self.tr("Cancel"))
|
|
80
|
+
self.cancel_btn.clicked.connect(self.reject)
|
|
81
|
+
button_layout.addWidget(self.cancel_btn)
|
|
82
|
+
|
|
83
|
+
self.ok_btn = QPushButton(self.tr("OK"))
|
|
84
|
+
self.ok_btn.clicked.connect(self._on_ok)
|
|
85
|
+
button_layout.addWidget(self.ok_btn)
|
|
86
|
+
|
|
87
|
+
main_layout.addLayout(button_layout)
|
|
88
|
+
|
|
89
|
+
def _setup_basic_tab(self):
|
|
90
|
+
"""Basic settings tab"""
|
|
91
|
+
layout = QVBoxLayout(self.basic_tab)
|
|
92
|
+
|
|
93
|
+
# ★ Project name
|
|
94
|
+
project_group = QGroupBox(self.tr("Project settings"))
|
|
95
|
+
project_layout = QFormLayout(project_group)
|
|
96
|
+
|
|
97
|
+
self.project_name_edit = QLineEdit()
|
|
98
|
+
self.project_name_edit.setPlaceholderText(self.tr("Example: MyProject"))
|
|
99
|
+
self.project_name_edit.setToolTip(self.tr("Used as the generated file name <project_name>_run.c"))
|
|
100
|
+
project_layout.addRow("Project name:", self.project_name_edit)
|
|
101
|
+
|
|
102
|
+
layout.addWidget(project_group)
|
|
103
|
+
|
|
104
|
+
# Generation style (fixed display)
|
|
105
|
+
style_group = QGroupBox(self.tr("Generation style"))
|
|
106
|
+
style_layout = QFormLayout(style_group)
|
|
107
|
+
|
|
108
|
+
# Generation style: fixed
|
|
109
|
+
style_value_label = QLabel(self.tr("Table-driven style (cell-level function + function table)"))
|
|
110
|
+
style_value_label.setStyleSheet("font-weight: bold;")
|
|
111
|
+
style_layout.addRow("Generation style:", style_value_label)
|
|
112
|
+
|
|
113
|
+
# Table style: fixed
|
|
114
|
+
table_value_label = QLabel(self.tr("Array style (2D array + O(1) access)"))
|
|
115
|
+
table_value_label.setStyleSheet("font-weight: bold;")
|
|
116
|
+
style_layout.addRow("Table style:", table_value_label)
|
|
117
|
+
|
|
118
|
+
# description
|
|
119
|
+
note_label = QLabel(
|
|
120
|
+
self.tr("* Fixed to a style optimized for C.\n"
|
|
121
|
+
" Generates cell-level transition functions, managed by a function table.")
|
|
122
|
+
)
|
|
123
|
+
note_label.setStyleSheet("color: gray; font-size: 10px; margin-left: 10px;")
|
|
124
|
+
style_layout.addRow("", note_label)
|
|
125
|
+
|
|
126
|
+
# OS type (this is meaningful, so it is selectable)
|
|
127
|
+
self.os_type_combo = QComboBox()
|
|
128
|
+
self.os_type_combo.addItem(self.tr("NonRTOS (bare metal)"), "non_rtos")
|
|
129
|
+
self.os_type_combo.addItem(self.tr("FreeRTOS"), "freertos")
|
|
130
|
+
self.os_type_combo.addItem(self.tr("ThreadX"), "threadx")
|
|
131
|
+
style_layout.addRow("OS type:", self.os_type_combo)
|
|
132
|
+
|
|
133
|
+
layout.addWidget(style_group)
|
|
134
|
+
|
|
135
|
+
# Naming convention
|
|
136
|
+
naming_group = QGroupBox(self.tr("Naming convention"))
|
|
137
|
+
naming_layout = QFormLayout(naming_group)
|
|
138
|
+
|
|
139
|
+
self.naming_prefix_edit = QLineEdit()
|
|
140
|
+
self.naming_prefix_edit.setPlaceholderText(self.tr("Function name prefix (optional)"))
|
|
141
|
+
naming_layout.addRow("Prefix:", self.naming_prefix_edit)
|
|
142
|
+
|
|
143
|
+
self.state_prefix_edit = QLineEdit()
|
|
144
|
+
naming_layout.addRow("State prefix:", self.state_prefix_edit)
|
|
145
|
+
|
|
146
|
+
self.event_prefix_edit = QLineEdit()
|
|
147
|
+
naming_layout.addRow("Event prefix:", self.event_prefix_edit)
|
|
148
|
+
|
|
149
|
+
self.flag_prefix_edit = QLineEdit()
|
|
150
|
+
naming_layout.addRow("Flag prefix:", self.flag_prefix_edit)
|
|
151
|
+
|
|
152
|
+
layout.addWidget(naming_group)
|
|
153
|
+
|
|
154
|
+
# Comment settings
|
|
155
|
+
comment_group = QGroupBox(self.tr("Comment settings"))
|
|
156
|
+
comment_layout = QVBoxLayout(comment_group)
|
|
157
|
+
|
|
158
|
+
self.enable_comments_check = QCheckBox(self.tr("Generate comments"))
|
|
159
|
+
comment_layout.addWidget(self.enable_comments_check)
|
|
160
|
+
|
|
161
|
+
self.enable_doxygen_check = QCheckBox(self.tr("Generate Doxygen-style comments"))
|
|
162
|
+
comment_layout.addWidget(self.enable_doxygen_check)
|
|
163
|
+
|
|
164
|
+
self.enable_markers_check = QCheckBox(self.tr("Generate user code markers"))
|
|
165
|
+
comment_layout.addWidget(self.enable_markers_check)
|
|
166
|
+
|
|
167
|
+
layout.addWidget(comment_group)
|
|
168
|
+
layout.addStretch()
|
|
169
|
+
|
|
170
|
+
def _setup_log_tab(self):
|
|
171
|
+
"""Log settings tab"""
|
|
172
|
+
layout = QVBoxLayout(self.log_tab)
|
|
173
|
+
|
|
174
|
+
log_group = QGroupBox(self.tr("Debug log settings"))
|
|
175
|
+
log_layout = QVBoxLayout(log_group)
|
|
176
|
+
|
|
177
|
+
self.enable_debug_logs_check = QCheckBox(self.tr("Generate DEBUG logs"))
|
|
178
|
+
log_layout.addWidget(self.enable_debug_logs_check)
|
|
179
|
+
|
|
180
|
+
self.enable_info_logs_check = QCheckBox(self.tr("Generate INFO logs"))
|
|
181
|
+
log_layout.addWidget(self.enable_info_logs_check)
|
|
182
|
+
|
|
183
|
+
self.enable_error_logs_check = QCheckBox(self.tr("Generate ERROR logs"))
|
|
184
|
+
log_layout.addWidget(self.enable_error_logs_check)
|
|
185
|
+
|
|
186
|
+
layout.addWidget(log_group)
|
|
187
|
+
|
|
188
|
+
# Pending event limit
|
|
189
|
+
pending_group = QGroupBox(self.tr("Pending event settings"))
|
|
190
|
+
pending_layout = QFormLayout(pending_group)
|
|
191
|
+
|
|
192
|
+
self.max_pending_spin = QSpinBox()
|
|
193
|
+
self.max_pending_spin.setRange(1, 255)
|
|
194
|
+
self.max_pending_spin.setValue(16)
|
|
195
|
+
self.max_pending_spin.setToolTip(
|
|
196
|
+
self.tr("Upper limit of consecutive pending events.\n"
|
|
197
|
+
"Processing is aborted beyond this count to prevent infinite loops.")
|
|
198
|
+
)
|
|
199
|
+
pending_layout.addRow("Max consecutive processing:", self.max_pending_spin)
|
|
200
|
+
|
|
201
|
+
layout.addWidget(pending_group)
|
|
202
|
+
layout.addStretch()
|
|
203
|
+
|
|
204
|
+
def _setup_include_tab(self):
|
|
205
|
+
"""External include settings tab"""
|
|
206
|
+
layout = QVBoxLayout(self.include_tab)
|
|
207
|
+
|
|
208
|
+
# External include file
|
|
209
|
+
include_group = QGroupBox(self.tr("External include file"))
|
|
210
|
+
include_layout = QVBoxLayout(include_group)
|
|
211
|
+
|
|
212
|
+
hint_label = QLabel(
|
|
213
|
+
self.tr("Specify a generated header such as Renesas Smart Configurator output.\n"
|
|
214
|
+
"The specified header is #include'd into the selected insertion target.")
|
|
215
|
+
)
|
|
216
|
+
hint_label.setStyleSheet("color: gray; font-size: 10px;")
|
|
217
|
+
include_layout.addWidget(hint_label)
|
|
218
|
+
|
|
219
|
+
self.include_list = QListWidget()
|
|
220
|
+
self.include_list.setSelectionMode(QAbstractItemView.SingleSelection)
|
|
221
|
+
self.include_list.setMinimumHeight(120)
|
|
222
|
+
include_layout.addWidget(self.include_list)
|
|
223
|
+
|
|
224
|
+
include_btn_layout = QHBoxLayout()
|
|
225
|
+
|
|
226
|
+
add_btn = QPushButton(self.tr("Add..."))
|
|
227
|
+
add_btn.clicked.connect(self._on_add_include)
|
|
228
|
+
include_btn_layout.addWidget(add_btn)
|
|
229
|
+
|
|
230
|
+
remove_btn = QPushButton(self.tr("Delete"))
|
|
231
|
+
remove_btn.clicked.connect(self._on_remove_include)
|
|
232
|
+
include_btn_layout.addWidget(remove_btn)
|
|
233
|
+
|
|
234
|
+
up_btn = QPushButton(self.tr("Move up"))
|
|
235
|
+
up_btn.clicked.connect(self._on_move_include_up)
|
|
236
|
+
include_btn_layout.addWidget(up_btn)
|
|
237
|
+
|
|
238
|
+
down_btn = QPushButton(self.tr("Move down"))
|
|
239
|
+
down_btn.clicked.connect(self._on_move_include_down)
|
|
240
|
+
include_btn_layout.addWidget(down_btn)
|
|
241
|
+
|
|
242
|
+
include_btn_layout.addStretch()
|
|
243
|
+
include_layout.addLayout(include_btn_layout)
|
|
244
|
+
|
|
245
|
+
layout.addWidget(include_group)
|
|
246
|
+
|
|
247
|
+
# Insertion target
|
|
248
|
+
target_group = QGroupBox(self.tr("Insertion target"))
|
|
249
|
+
target_layout = QVBoxLayout(target_group)
|
|
250
|
+
|
|
251
|
+
self.include_in_super_check = QCheckBox(self.tr("statable_all.h (for user main.c)"))
|
|
252
|
+
target_layout.addWidget(self.include_in_super_check)
|
|
253
|
+
|
|
254
|
+
self.include_in_role_check = QCheckBox(self.tr("Role function .c file"))
|
|
255
|
+
target_layout.addWidget(self.include_in_role_check)
|
|
256
|
+
|
|
257
|
+
self.include_in_transitions_check = QCheckBox(self.tr("transitions .c file"))
|
|
258
|
+
target_layout.addWidget(self.include_in_transitions_check)
|
|
259
|
+
|
|
260
|
+
self.include_in_common_check = QCheckBox(self.tr("common .c file"))
|
|
261
|
+
target_layout.addWidget(self.include_in_common_check)
|
|
262
|
+
|
|
263
|
+
layout.addWidget(target_group)
|
|
264
|
+
layout.addStretch()
|
|
265
|
+
|
|
266
|
+
def _setup_output_tab(self):
|
|
267
|
+
"""Output settings tab"""
|
|
268
|
+
layout = QVBoxLayout(self.output_tab)
|
|
269
|
+
|
|
270
|
+
# Output settings
|
|
271
|
+
output_group = QGroupBox(self.tr("Output settings"))
|
|
272
|
+
output_layout = QFormLayout(output_group)
|
|
273
|
+
|
|
274
|
+
self.output_dir_edit = QLineEdit()
|
|
275
|
+
self.output_dir_edit.setPlaceholderText(self.tr("Output directory"))
|
|
276
|
+
self.output_dir_btn = QPushButton(self.tr("Browse..."))
|
|
277
|
+
self.output_dir_btn.clicked.connect(self._select_output_dir)
|
|
278
|
+
|
|
279
|
+
output_dir_layout = QHBoxLayout()
|
|
280
|
+
output_dir_layout.addWidget(self.output_dir_edit)
|
|
281
|
+
output_dir_layout.addWidget(self.output_dir_btn)
|
|
282
|
+
|
|
283
|
+
output_layout.addRow("Output directory:", output_dir_layout)
|
|
284
|
+
|
|
285
|
+
layout.addWidget(output_group)
|
|
286
|
+
|
|
287
|
+
# Folder structure
|
|
288
|
+
folder_group = QGroupBox(self.tr("Folder structure"))
|
|
289
|
+
folder_layout = QFormLayout(folder_group)
|
|
290
|
+
|
|
291
|
+
self.folder_structure_combo = QComboBox()
|
|
292
|
+
self.folder_structure_combo.addItem(self.tr("include/src separation (recommended)"), "by_type")
|
|
293
|
+
self.folder_structure_combo.addItem(self.tr("Per layer"), "by_layer")
|
|
294
|
+
self.folder_structure_combo.addItem(self.tr("Flat"), "flat")
|
|
295
|
+
folder_layout.addRow("Structure:", self.folder_structure_combo)
|
|
296
|
+
|
|
297
|
+
self.include_dir_edit = QLineEdit()
|
|
298
|
+
folder_layout.addRow("include folder name:", self.include_dir_edit)
|
|
299
|
+
|
|
300
|
+
self.source_dir_edit = QLineEdit()
|
|
301
|
+
folder_layout.addRow("src folder name:", self.source_dir_edit)
|
|
302
|
+
|
|
303
|
+
self.common_dir_edit = QLineEdit()
|
|
304
|
+
folder_layout.addRow("Common folder name:", self.common_dir_edit)
|
|
305
|
+
|
|
306
|
+
self.project_dir_edit = QLineEdit()
|
|
307
|
+
folder_layout.addRow("Project folder name:", self.project_dir_edit)
|
|
308
|
+
|
|
309
|
+
layout.addWidget(folder_group)
|
|
310
|
+
|
|
311
|
+
# Super include
|
|
312
|
+
super_group = QGroupBox(self.tr("Super include"))
|
|
313
|
+
super_layout = QVBoxLayout(super_group)
|
|
314
|
+
|
|
315
|
+
self.generate_super_check = QCheckBox(self.tr("Generate statable_all.h (for user main.c)"))
|
|
316
|
+
super_layout.addWidget(self.generate_super_check)
|
|
317
|
+
|
|
318
|
+
super_form = QFormLayout()
|
|
319
|
+
self.super_include_name_edit = QLineEdit()
|
|
320
|
+
super_form.addRow("File name:", self.super_include_name_edit)
|
|
321
|
+
|
|
322
|
+
self.super_include_dir_edit = QLineEdit()
|
|
323
|
+
super_form.addRow("Placement folder:", self.super_include_dir_edit)
|
|
324
|
+
|
|
325
|
+
super_layout.addLayout(super_form)
|
|
326
|
+
|
|
327
|
+
layout.addWidget(super_group)
|
|
328
|
+
|
|
329
|
+
# Merge settings
|
|
330
|
+
merge_group = QGroupBox(self.tr("Merge settings"))
|
|
331
|
+
merge_layout = QVBoxLayout(merge_group)
|
|
332
|
+
|
|
333
|
+
self.save_with_merge_check = QCheckBox(self.tr("Save by merging with existing file (preserve user code)"))
|
|
334
|
+
merge_layout.addWidget(self.save_with_merge_check)
|
|
335
|
+
|
|
336
|
+
layout.addWidget(merge_group)
|
|
337
|
+
layout.addStretch()
|
|
338
|
+
|
|
339
|
+
def _load_config(self):
|
|
340
|
+
# Project name
|
|
341
|
+
self.project_name_edit.setText(self.config.project_name)
|
|
342
|
+
|
|
343
|
+
# Generation style / table style are fixed, so force internal settings
|
|
344
|
+
self.config.generation_style = "table_driven"
|
|
345
|
+
self.config.table_type = "array"
|
|
346
|
+
|
|
347
|
+
# OS type
|
|
348
|
+
idx = self.os_type_combo.findData(self.config.os_type)
|
|
349
|
+
if idx >= 0:
|
|
350
|
+
self.os_type_combo.setCurrentIndex(idx)
|
|
351
|
+
|
|
352
|
+
# Naming convention
|
|
353
|
+
self.naming_prefix_edit.setText(self.config.naming_prefix)
|
|
354
|
+
self.state_prefix_edit.setText(self.config.state_prefix)
|
|
355
|
+
self.event_prefix_edit.setText(self.config.event_prefix)
|
|
356
|
+
self.flag_prefix_edit.setText(self.config.flag_prefix)
|
|
357
|
+
|
|
358
|
+
# comment
|
|
359
|
+
self.enable_comments_check.setChecked(self.config.enable_comments)
|
|
360
|
+
self.enable_doxygen_check.setChecked(self.config.enable_doxygen)
|
|
361
|
+
self.enable_markers_check.setChecked(self.config.enable_user_markers)
|
|
362
|
+
|
|
363
|
+
# Log
|
|
364
|
+
self.enable_debug_logs_check.setChecked(self.config.enable_debug_logs)
|
|
365
|
+
self.enable_info_logs_check.setChecked(self.config.enable_info_logs)
|
|
366
|
+
self.enable_error_logs_check.setChecked(self.config.enable_error_logs)
|
|
367
|
+
|
|
368
|
+
# Pending event
|
|
369
|
+
self.max_pending_spin.setValue(self.config.max_consecutive_pending_events)
|
|
370
|
+
|
|
371
|
+
# External include
|
|
372
|
+
self.include_list.clear()
|
|
373
|
+
for inc in self.config.external_includes:
|
|
374
|
+
self.include_list.addItem(inc)
|
|
375
|
+
|
|
376
|
+
self.include_in_super_check.setChecked(self.config.external_includes_in_super)
|
|
377
|
+
self.include_in_role_check.setChecked(self.config.external_includes_in_role)
|
|
378
|
+
self.include_in_transitions_check.setChecked(self.config.external_includes_in_transitions)
|
|
379
|
+
self.include_in_common_check.setChecked(self.config.external_includes_in_common)
|
|
380
|
+
|
|
381
|
+
# Output
|
|
382
|
+
self.output_dir_edit.setText(self.config.output_directory)
|
|
383
|
+
self.save_with_merge_check.setChecked(self.config.save_with_merge)
|
|
384
|
+
|
|
385
|
+
# Folder structure
|
|
386
|
+
idx = self.folder_structure_combo.findData(self.config.folder_structure)
|
|
387
|
+
if idx >= 0:
|
|
388
|
+
self.folder_structure_combo.setCurrentIndex(idx)
|
|
389
|
+
|
|
390
|
+
self.include_dir_edit.setText(self.config.include_dir_name)
|
|
391
|
+
self.source_dir_edit.setText(self.config.source_dir_name)
|
|
392
|
+
self.common_dir_edit.setText(self.config.common_dir_name)
|
|
393
|
+
self.project_dir_edit.setText(self.config.project_dir_name)
|
|
394
|
+
|
|
395
|
+
# Super include
|
|
396
|
+
self.generate_super_check.setChecked(self.config.generate_super_include)
|
|
397
|
+
self.super_include_name_edit.setText(self.config.super_include_file)
|
|
398
|
+
self.super_include_dir_edit.setText(self.config.super_include_dir)
|
|
399
|
+
|
|
400
|
+
def _save_config(self):
|
|
401
|
+
# Project name
|
|
402
|
+
self.config.project_name = self.project_name_edit.text().strip() or "MyProject"
|
|
403
|
+
|
|
404
|
+
# Generation style / table style fixed
|
|
405
|
+
self.config.generation_style = "table_driven"
|
|
406
|
+
self.config.table_type = "array"
|
|
407
|
+
|
|
408
|
+
# OS type
|
|
409
|
+
self.config.os_type = self.os_type_combo.currentData()
|
|
410
|
+
|
|
411
|
+
# Naming convention
|
|
412
|
+
self.config.naming_prefix = self.naming_prefix_edit.text()
|
|
413
|
+
self.config.state_prefix = self.state_prefix_edit.text() or "STATE"
|
|
414
|
+
self.config.event_prefix = self.event_prefix_edit.text() or "EVENT"
|
|
415
|
+
self.config.flag_prefix = self.flag_prefix_edit.text() or "FLAG"
|
|
416
|
+
|
|
417
|
+
# comment
|
|
418
|
+
self.config.enable_comments = self.enable_comments_check.isChecked()
|
|
419
|
+
self.config.enable_doxygen = self.enable_doxygen_check.isChecked()
|
|
420
|
+
self.config.enable_user_markers = self.enable_markers_check.isChecked()
|
|
421
|
+
|
|
422
|
+
# Log
|
|
423
|
+
self.config.enable_debug_logs = self.enable_debug_logs_check.isChecked()
|
|
424
|
+
self.config.enable_info_logs = self.enable_info_logs_check.isChecked()
|
|
425
|
+
self.config.enable_error_logs = self.enable_error_logs_check.isChecked()
|
|
426
|
+
|
|
427
|
+
# Pending event
|
|
428
|
+
self.config.max_consecutive_pending_events = self.max_pending_spin.value()
|
|
429
|
+
|
|
430
|
+
# External include
|
|
431
|
+
self.config.external_includes = [
|
|
432
|
+
self.include_list.item(i).text()
|
|
433
|
+
for i in range(self.include_list.count())
|
|
434
|
+
]
|
|
435
|
+
self.config.external_includes_in_super = self.include_in_super_check.isChecked()
|
|
436
|
+
self.config.external_includes_in_role = self.include_in_role_check.isChecked()
|
|
437
|
+
self.config.external_includes_in_transitions = self.include_in_transitions_check.isChecked()
|
|
438
|
+
self.config.external_includes_in_common = self.include_in_common_check.isChecked()
|
|
439
|
+
|
|
440
|
+
# Output
|
|
441
|
+
self.config.output_directory = self.output_dir_edit.text()
|
|
442
|
+
self.config.save_with_merge = self.save_with_merge_check.isChecked()
|
|
443
|
+
|
|
444
|
+
# Folder structure
|
|
445
|
+
self.config.folder_structure = self.folder_structure_combo.currentData()
|
|
446
|
+
self.config.include_dir_name = self.include_dir_edit.text() or "include"
|
|
447
|
+
self.config.source_dir_name = self.source_dir_edit.text() or "src"
|
|
448
|
+
self.config.common_dir_name = self.common_dir_edit.text() or "common"
|
|
449
|
+
self.config.project_dir_name = self.project_dir_edit.text() or "project"
|
|
450
|
+
|
|
451
|
+
# Super include
|
|
452
|
+
self.config.generate_super_include = self.generate_super_check.isChecked()
|
|
453
|
+
self.config.super_include_file = self.super_include_name_edit.text() or "statable_all.h"
|
|
454
|
+
self.config.super_include_dir = self.super_include_dir_edit.text() or "common"
|
|
455
|
+
|
|
456
|
+
self.config_manager.set_config(self.config)
|
|
457
|
+
|
|
458
|
+
def _on_ok(self):
|
|
459
|
+
"""OK button"""
|
|
460
|
+
self._save_config()
|
|
461
|
+
self.accept()
|
|
462
|
+
|
|
463
|
+
def _on_reset(self):
|
|
464
|
+
"""Reset button"""
|
|
465
|
+
reply = QMessageBox.question(
|
|
466
|
+
self, self.tr("Confirm"), self.tr("Reset settings?"),
|
|
467
|
+
QMessageBox.Yes | QMessageBox.No
|
|
468
|
+
)
|
|
469
|
+
if reply == QMessageBox.Yes:
|
|
470
|
+
self.config_manager.reset()
|
|
471
|
+
self.config = self.config_manager.get_config()
|
|
472
|
+
self._load_config()
|
|
473
|
+
|
|
474
|
+
def _select_output_dir(self):
|
|
475
|
+
"""Select output directory"""
|
|
476
|
+
current = self.output_dir_edit.text() or os.getcwd()
|
|
477
|
+
dir_path = QFileDialog.getExistingDirectory(
|
|
478
|
+
self, "Select output directory", current
|
|
479
|
+
)
|
|
480
|
+
if dir_path:
|
|
481
|
+
self.output_dir_edit.setText(dir_path)
|
|
482
|
+
|
|
483
|
+
# ===== External include operations =====
|
|
484
|
+
def _on_add_include(self):
|
|
485
|
+
files, _ = QFileDialog.getOpenFileNames(
|
|
486
|
+
self, "Select external include file", "",
|
|
487
|
+
"Header files (*.h);;All files (*)"
|
|
488
|
+
)
|
|
489
|
+
if files:
|
|
490
|
+
for f in files:
|
|
491
|
+
# Extract only the file name from the path (consistent with existing registration)
|
|
492
|
+
name = os.path.basename(f)
|
|
493
|
+
# Duplicate check
|
|
494
|
+
existing = [
|
|
495
|
+
self.include_list.item(i).text()
|
|
496
|
+
for i in range(self.include_list.count())
|
|
497
|
+
]
|
|
498
|
+
if name not in existing:
|
|
499
|
+
self.include_list.addItem(name)
|
|
500
|
+
|
|
501
|
+
def _on_remove_include(self):
|
|
502
|
+
row = self.include_list.currentRow()
|
|
503
|
+
if row >= 0:
|
|
504
|
+
self.include_list.takeItem(row)
|
|
505
|
+
|
|
506
|
+
def _on_move_include_up(self):
|
|
507
|
+
row = self.include_list.currentRow()
|
|
508
|
+
if row > 0:
|
|
509
|
+
item = self.include_list.takeItem(row)
|
|
510
|
+
self.include_list.insertItem(row - 1, item)
|
|
511
|
+
self.include_list.setCurrentRow(row - 1)
|
|
512
|
+
|
|
513
|
+
def _on_move_include_down(self):
|
|
514
|
+
row = self.include_list.currentRow()
|
|
515
|
+
if 0 <= row < self.include_list.count() - 1:
|
|
516
|
+
item = self.include_list.takeItem(row)
|
|
517
|
+
self.include_list.insertItem(row + 1, item)
|
|
518
|
+
self.include_list.setCurrentRow(row + 1)
|
|
519
|
+
|
|
520
|
+
def get_config(self) -> CodeGenerationConfig:
|
|
521
|
+
"""Get settings"""
|
|
522
|
+
return self.config
|