statable 3.1.1__tar.gz → 3.2.1__tar.gz

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.
Files changed (165) hide show
  1. {statable-3.1.1 → statable-3.2.1}/PKG-INFO +1 -1
  2. {statable-3.1.1 → statable-3.2.1}/codegen/__init__.py +1 -1
  3. {statable-3.1.1 → statable-3.2.1}/pyproject.toml +1 -1
  4. {statable-3.1.1 → statable-3.2.1}/statable/__init__.py +1 -1
  5. {statable-3.1.1 → statable-3.2.1}/statable/cli.py +1 -1
  6. {statable-3.1.1 → statable-3.2.1}/statable.egg-info/PKG-INFO +1 -1
  7. {statable-3.1.1 → statable-3.2.1}/statable.egg-info/SOURCES.txt +4 -1
  8. {statable-3.1.1 → statable-3.2.1}/statable_gui/i18n/__init__.py +11 -1
  9. {statable-3.1.1 → statable-3.2.1}/statable_gui/main_window.py +61 -16
  10. statable-3.2.1/statable_gui/new_project_templates.py +133 -0
  11. statable-3.2.1/statable_gui/new_project_wizard.py +551 -0
  12. {statable-3.1.1 → statable-3.2.1}/tests/test_v3_0_s1_packaging.py +9 -9
  13. {statable-3.1.1 → statable-3.2.1}/tests/test_v3_0_s2_public_api.py +4 -4
  14. {statable-3.1.1 → statable-3.2.1}/tests/test_v3_0_s3_cli.py +4 -4
  15. {statable-3.1.1 → statable-3.2.1}/tests/test_v3_0_s4_docs.py +5 -5
  16. statable-3.2.1/tests/test_v3_2_s1_wizard.py +219 -0
  17. {statable-3.1.1 → statable-3.2.1}/README.md +0 -0
  18. {statable-3.1.1 → statable-3.2.1}/codegen/c_code_generator.py +0 -0
  19. {statable-3.1.1 → statable-3.2.1}/codegen/code_merger.py +0 -0
  20. {statable-3.1.1 → statable-3.2.1}/codegen/code_templates.py +0 -0
  21. {statable-3.1.1 → statable-3.2.1}/codegen/config.py +0 -0
  22. {statable-3.1.1 → statable-3.2.1}/codegen/enum_generator.py +0 -0
  23. {statable-3.1.1 → statable-3.2.1}/codegen/event_queue_generator.py +0 -0
  24. {statable-3.1.1 → statable-3.2.1}/codegen/interrupt_generator.py +0 -0
  25. {statable-3.1.1 → statable-3.2.1}/codegen/naming_convention.py +0 -0
  26. {statable-3.1.1 → statable-3.2.1}/codegen/osal_generator.py +0 -0
  27. {statable-3.1.1 → statable-3.2.1}/codegen/role_function_generator.py +0 -0
  28. {statable-3.1.1 → statable-3.2.1}/codegen/sample_data.py +0 -0
  29. {statable-3.1.1 → statable-3.2.1}/codegen/state_actions_generator.py +0 -0
  30. {statable-3.1.1 → statable-3.2.1}/codegen/struct_generator.py +0 -0
  31. {statable-3.1.1 → statable-3.2.1}/codegen/timer_generator.py +0 -0
  32. {statable-3.1.1 → statable-3.2.1}/codegen/transition_generator.py +0 -0
  33. {statable-3.1.1 → statable-3.2.1}/codegen/type_mapper.py +0 -0
  34. {statable-3.1.1 → statable-3.2.1}/codegen/validate/__init__.py +0 -0
  35. {statable-3.1.1 → statable-3.2.1}/codegen/validate/change_actions.py +0 -0
  36. {statable-3.1.1 → statable-3.2.1}/codegen/validate/change_applier.py +0 -0
  37. {statable-3.1.1 → statable-3.2.1}/codegen/validate/clipboard_manager.py +0 -0
  38. {statable-3.1.1 → statable-3.2.1}/codegen/validate/data/__init__.py +0 -0
  39. {statable-3.1.1 → statable-3.2.1}/codegen/validate/data/action_definitions.py +0 -0
  40. {statable-3.1.1 → statable-3.2.1}/codegen/validate/data/keywords.py +0 -0
  41. {statable-3.1.1 → statable-3.2.1}/codegen/validate/data/prompt_templates.py +0 -0
  42. {statable-3.1.1 → statable-3.2.1}/codegen/validate/data/validation_rules.py +0 -0
  43. {statable-3.1.1 → statable-3.2.1}/codegen/validate/items/__init__.py +0 -0
  44. {statable-3.1.1 → statable-3.2.1}/codegen/validate/items/base_validator.py +0 -0
  45. {statable-3.1.1 → statable-3.2.1}/codegen/validate/items/cell_validator.py +0 -0
  46. {statable-3.1.1 → statable-3.2.1}/codegen/validate/items/custom_type_validator.py +0 -0
  47. {statable-3.1.1 → statable-3.2.1}/codegen/validate/items/event_validator.py +0 -0
  48. {statable-3.1.1 → statable-3.2.1}/codegen/validate/items/flag_validator.py +0 -0
  49. {statable-3.1.1 → statable-3.2.1}/codegen/validate/items/interrupt_validator.py +0 -0
  50. {statable-3.1.1 → statable-3.2.1}/codegen/validate/items/queue_validator.py +0 -0
  51. {statable-3.1.1 → statable-3.2.1}/codegen/validate/items/role_function_validator.py +0 -0
  52. {statable-3.1.1 → statable-3.2.1}/codegen/validate/items/state_validator.py +0 -0
  53. {statable-3.1.1 → statable-3.2.1}/codegen/validate/items/timer_validator.py +0 -0
  54. {statable-3.1.1 → statable-3.2.1}/codegen/validate/items/transition_validator.py +0 -0
  55. {statable-3.1.1 → statable-3.2.1}/codegen/validate/items/variable_validator.py +0 -0
  56. {statable-3.1.1 → statable-3.2.1}/codegen/validate/logger.py +0 -0
  57. {statable-3.1.1 → statable-3.2.1}/codegen/validate/models.py +0 -0
  58. {statable-3.1.1 → statable-3.2.1}/codegen/validate/prompt_generator.py +0 -0
  59. {statable-3.1.1 → statable-3.2.1}/codegen/validate/response_parser.py +0 -0
  60. {statable-3.1.1 → statable-3.2.1}/codegen/validate/response_validator.py +0 -0
  61. {statable-3.1.1 → statable-3.2.1}/codegen/validate/validation_dialog.py +0 -0
  62. {statable-3.1.1 → statable-3.2.1}/codegen/validate/validator.py +0 -0
  63. {statable-3.1.1 → statable-3.2.1}/codegen/variable_generator.py +0 -0
  64. {statable-3.1.1 → statable-3.2.1}/setup.cfg +0 -0
  65. {statable-3.1.1 → statable-3.2.1}/statable/__main__.py +0 -0
  66. {statable-3.1.1 → statable-3.2.1}/statable/global_defs.py +0 -0
  67. {statable-3.1.1 → statable-3.2.1}/statable/mermaid_gen.py +0 -0
  68. {statable-3.1.1 → statable-3.2.1}/statable/model.py +0 -0
  69. {statable-3.1.1 → statable-3.2.1}/statable/parser.py +0 -0
  70. {statable-3.1.1 → statable-3.2.1}/statable/sample_data.py +0 -0
  71. {statable-3.1.1 → statable-3.2.1}/statable/shared/__init__.py +0 -0
  72. {statable-3.1.1 → statable-3.2.1}/statable/shared/condition_library.py +0 -0
  73. {statable-3.1.1 → statable-3.2.1}/statable/shared/literal_library.py +0 -0
  74. {statable-3.1.1 → statable-3.2.1}/statable/shared/role_function_library.py +0 -0
  75. {statable-3.1.1 → statable-3.2.1}/statable/state_machine.py +0 -0
  76. {statable-3.1.1 → statable-3.2.1}/statable/xml_io.py +0 -0
  77. {statable-3.1.1 → statable-3.2.1}/statable.egg-info/dependency_links.txt +0 -0
  78. {statable-3.1.1 → statable-3.2.1}/statable.egg-info/entry_points.txt +0 -0
  79. {statable-3.1.1 → statable-3.2.1}/statable.egg-info/requires.txt +0 -0
  80. {statable-3.1.1 → statable-3.2.1}/statable.egg-info/top_level.txt +0 -0
  81. {statable-3.1.1 → statable-3.2.1}/statable_gui/__init__.py +0 -0
  82. {statable-3.1.1 → statable-3.2.1}/statable_gui/action_edit_dialog.py +0 -0
  83. {statable-3.1.1 → statable-3.2.1}/statable_gui/code_generation_dialog.py +0 -0
  84. {statable-3.1.1 → statable-3.2.1}/statable_gui/code_generation_settings_dialog.py +0 -0
  85. {statable-3.1.1 → statable-3.2.1}/statable_gui/common_widgets.py +0 -0
  86. {statable-3.1.1 → statable-3.2.1}/statable_gui/condition_builder_dialog.py +0 -0
  87. {statable-3.1.1 → statable-3.2.1}/statable_gui/condition_edit_dialog.py +0 -0
  88. {statable-3.1.1 → statable-3.2.1}/statable_gui/condition_template_dialog.py +0 -0
  89. {statable-3.1.1 → statable-3.2.1}/statable_gui/config.py +0 -0
  90. {statable-3.1.1 → statable-3.2.1}/statable_gui/dialogs.py +0 -0
  91. {statable-3.1.1 → statable-3.2.1}/statable_gui/event_definition_dialog.py +0 -0
  92. {statable-3.1.1 → statable-3.2.1}/statable_gui/event_delivery_settings_dialog.py +0 -0
  93. {statable-3.1.1 → statable-3.2.1}/statable_gui/event_queue_dialog.py +0 -0
  94. {statable-3.1.1 → statable-3.2.1}/statable_gui/global_defs.py +0 -0
  95. {statable-3.1.1 → statable-3.2.1}/statable_gui/global_defs_dialog.py +0 -0
  96. {statable-3.1.1 → statable-3.2.1}/statable_gui/interrupt_handler_edit_dialog.py +0 -0
  97. {statable-3.1.1 → statable-3.2.1}/statable_gui/layer_settings_dialog.py +0 -0
  98. {statable-3.1.1 → statable-3.2.1}/statable_gui/libcntrl/__init__.py +0 -0
  99. {statable-3.1.1 → statable-3.2.1}/statable_gui/libcntrl/condition_library.py +0 -0
  100. {statable-3.1.1 → statable-3.2.1}/statable_gui/libcntrl/literal_library.py +0 -0
  101. {statable-3.1.1 → statable-3.2.1}/statable_gui/libcntrl/literal_management_dialog.py +0 -0
  102. {statable-3.1.1 → statable-3.2.1}/statable_gui/libcntrl/role_function_edit_dialog.py +0 -0
  103. {statable-3.1.1 → statable-3.2.1}/statable_gui/libcntrl/role_function_library.py +0 -0
  104. {statable-3.1.1 → statable-3.2.1}/statable_gui/literal_definition_dialog.py +0 -0
  105. {statable-3.1.1 → statable-3.2.1}/statable_gui/logger.py +0 -0
  106. {statable-3.1.1 → statable-3.2.1}/statable_gui/matrix_table.py +0 -0
  107. {statable-3.1.1 → statable-3.2.1}/statable_gui/preference_keys.py +0 -0
  108. {statable-3.1.1 → statable-3.2.1}/statable_gui/preferences.py +0 -0
  109. {statable-3.1.1 → statable-3.2.1}/statable_gui/role_function_dialog.py +0 -0
  110. {statable-3.1.1 → statable-3.2.1}/statable_gui/sample_data.py +0 -0
  111. {statable-3.1.1 → statable-3.2.1}/statable_gui/state_actions_dialog.py +0 -0
  112. {statable-3.1.1 → statable-3.2.1}/statable_gui/symbol_picker.py +0 -0
  113. {statable-3.1.1 → statable-3.2.1}/statable_gui/traceball.py +0 -0
  114. {statable-3.1.1 → statable-3.2.1}/statable_gui/transition_editor_direct/__init__.py +0 -0
  115. {statable-3.1.1 → statable-3.2.1}/statable_gui/transition_editor_direct/actions_tab.py +0 -0
  116. {statable-3.1.1 → statable-3.2.1}/statable_gui/transition_editor_direct/code_widget.py +0 -0
  117. {statable-3.1.1 → statable-3.2.1}/statable_gui/transition_editor_direct/coverage_analyzer.py +0 -0
  118. {statable-3.1.1 → statable-3.2.1}/statable_gui/transition_editor_direct/dialog.py +0 -0
  119. {statable-3.1.1 → statable-3.2.1}/statable_gui/transition_editor_direct/draft.py +0 -0
  120. {statable-3.1.1 → statable-3.2.1}/statable_gui/transition_editor_direct/edit_dialogs.py +0 -0
  121. {statable-3.1.1 → statable-3.2.1}/statable_gui/transition_editor_direct/overview_tab.py +0 -0
  122. {statable-3.1.1 → statable-3.2.1}/statable_gui/transition_editor_direct/palette_widget.py +0 -0
  123. {statable-3.1.1 → statable-3.2.1}/statable_gui/transition_editor_direct/relations_edit_dialog.py +0 -0
  124. {statable-3.1.1 → statable-3.2.1}/statable_gui/transition_editor_direct/relations_tab.py +0 -0
  125. {statable-3.1.1 → statable-3.2.1}/statable_gui/transition_editor_direct/system_global_dialog.py +0 -0
  126. {statable-3.1.1 → statable-3.2.1}/statable_gui/transition_editor_direct/transition_actions_dialog.py +0 -0
  127. {statable-3.1.1 → statable-3.2.1}/statable_gui/transition_editor_direct/transitions_tab.py +0 -0
  128. {statable-3.1.1 → statable-3.2.1}/statable_gui/validation_dialog.py +0 -0
  129. {statable-3.1.1 → statable-3.2.1}/statable_gui/widgets.py +0 -0
  130. {statable-3.1.1 → statable-3.2.1}/tests/test_readme_consistency.py +0 -0
  131. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_2_p1.py +0 -0
  132. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_2_p12_10.py +0 -0
  133. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_2_p12_2.py +0 -0
  134. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_2_p12_5.py +0 -0
  135. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_2_p12_6.py +0 -0
  136. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_2_p12_7.py +0 -0
  137. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_2_p12_8.py +0 -0
  138. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_2_p12_9.py +0 -0
  139. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_2_p2.py +0 -0
  140. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_2_p3.py +0 -0
  141. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_2_p4a.py +0 -0
  142. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_2_p4b.py +0 -0
  143. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_3_p1.py +0 -0
  144. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_4_p1_merge.py +0 -0
  145. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_5_p1.py +0 -0
  146. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_5_p10.py +0 -0
  147. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_5_p11.py +0 -0
  148. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_5_p2.py +0 -0
  149. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_5_p3.py +0 -0
  150. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_5_p4.py +0 -0
  151. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_5_p5.py +0 -0
  152. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_5_p6.py +0 -0
  153. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_5_p8.py +0 -0
  154. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_5_p9.py +0 -0
  155. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_6_p1.py +0 -0
  156. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_6_p2.py +0 -0
  157. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_6_p3.py +0 -0
  158. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_7_p3.py +0 -0
  159. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_7_p4.py +0 -0
  160. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_7_p5_validation.py +0 -0
  161. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_8_p1_ai_prompt.py +0 -0
  162. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_8_p2_response_parser.py +0 -0
  163. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_8_p3_response_validator.py +0 -0
  164. {statable-3.1.1 → statable-3.2.1}/tests/test_v2_8_p4_gui_integration.py +0 -0
  165. {statable-3.1.1 → statable-3.2.1}/tests/test_v3_0_g1_shared.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: statable
3
- Version: 3.1.1
3
+ Version: 3.2.1
4
4
  Summary: MISRA C:2012-aware state machine design and C code generation for embedded systems
5
5
  Author: Hideki Akashi
6
6
  License-Expression: Apache-2.0
@@ -8,7 +8,7 @@ StaTable code generation layer
8
8
  so it is not re-exported at top level (to reduce startup time)
9
9
  """
10
10
 
11
- __version__ = "3.1.1"
11
+ __version__ = "3.2.1"
12
12
 
13
13
  __all__ = [
14
14
  'CCodeGenerator',
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "statable"
9
- version = "3.1.1"
9
+ version = "3.2.1"
10
10
  description = "MISRA C:2012-aware state machine design and C code generation for embedded systems"
11
11
  readme = "README.md"
12
12
  requires-python = ">=3.10"
@@ -40,7 +40,7 @@ from .global_defs import (
40
40
  StructMemberDef,
41
41
  )
42
42
 
43
- __version__ = "3.1.1"
43
+ __version__ = "3.2.1"
44
44
 
45
45
  __all__ = [
46
46
  # model
@@ -27,7 +27,7 @@ import json
27
27
  import sys
28
28
  from pathlib import Path
29
29
 
30
- CLI_VERSION = "3.1.1"
30
+ CLI_VERSION = "3.2.1"
31
31
 
32
32
 
33
33
  def _err(msg: str) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: statable
3
- Version: 3.1.1
3
+ Version: 3.2.1
4
4
  Summary: MISRA C:2012-aware state machine design and C code generation for embedded systems
5
5
  Author: Hideki Akashi
6
6
  License-Expression: Apache-2.0
@@ -88,6 +88,8 @@ statable_gui/literal_definition_dialog.py
88
88
  statable_gui/logger.py
89
89
  statable_gui/main_window.py
90
90
  statable_gui/matrix_table.py
91
+ statable_gui/new_project_templates.py
92
+ statable_gui/new_project_wizard.py
91
93
  statable_gui/preference_keys.py
92
94
  statable_gui/preferences.py
93
95
  statable_gui/role_function_dialog.py
@@ -157,4 +159,5 @@ tests/test_v3_0_g1_shared.py
157
159
  tests/test_v3_0_s1_packaging.py
158
160
  tests/test_v3_0_s2_public_api.py
159
161
  tests/test_v3_0_s3_cli.py
160
- tests/test_v3_0_s4_docs.py
162
+ tests/test_v3_0_s4_docs.py
163
+ tests/test_v3_2_s1_wizard.py
@@ -14,6 +14,7 @@ Usage in gui_main.py or statable_gui/main_window.py:
14
14
  """
15
15
  from __future__ import annotations
16
16
 
17
+ import sys
17
18
  from pathlib import Path
18
19
  from typing import Optional
19
20
 
@@ -25,7 +26,16 @@ from PySide6.QtCore import (
25
26
  )
26
27
  from PySide6.QtWidgets import QApplication
27
28
 
28
- I18N_DIR = Path(__file__).parent
29
+ # [v3.2] PyInstaller frozen support
30
+ if getattr(sys, "frozen", False):
31
+ # Bundled: resources are in sys._MEIPASS/statable_gui/i18n
32
+ _meipass = getattr(sys, "_MEIPASS", None)
33
+ if _meipass:
34
+ I18N_DIR = Path(_meipass) / "statable_gui" / "i18n"
35
+ else:
36
+ I18N_DIR = Path(__file__).parent
37
+ else:
38
+ I18N_DIR = Path(__file__).parent
29
39
  DEFAULT_LANG = "en"
30
40
  SUPPORTED_LANGUAGES = ["en", "zh_CN"]
31
41
  LANG_DISPLAY = {
@@ -39,7 +39,7 @@ from pathlib import Path
39
39
  from PySide6.QtCore import Qt
40
40
  from PySide6.QtGui import QAction
41
41
  from PySide6.QtWidgets import (
42
- QMainWindow, QTabWidget, QToolButton, QMessageBox,
42
+ QMainWindow, QTabWidget, QToolButton, QMessageBox, QDialog,
43
43
  QInputDialog, QFileDialog, QDialog, QToolBar
44
44
  )
45
45
 
@@ -211,6 +211,8 @@ class MainWindow(QMainWindow):
211
211
 
212
212
  self.tab_widget = QTabWidget()
213
213
  self.tab_widget.setTabsClosable(True)
214
+ # [v3.2.1] Enable drag-and-drop tab reordering
215
+ self.tab_widget.setMovable(True)
214
216
  self.tab_widget.tabCloseRequested.connect(
215
217
  self.close_tab)
216
218
  self.setCentralWidget(self.tab_widget)
@@ -375,16 +377,17 @@ class MainWindow(QMainWindow):
375
377
 
376
378
  file_menu = menubar.addMenu(self.tr("File"))
377
379
 
378
- # [v2.3] New Project (Ctrl+N)
379
- new_project_action = QAction(self.tr("New Project..."), self)
380
- new_project_action.setShortcut("Ctrl+N")
381
- new_project_action.triggered.connect(self.new_project)
382
- file_menu.addAction(new_project_action)
380
+ # [v3.2] New Project Wizard (Ctrl+N)
381
+ new_wizard_action = QAction(self.tr("New Project..."), self)
382
+ new_wizard_action.setShortcut("Ctrl+N")
383
+ new_wizard_action.triggered.connect(self.new_project_wizard)
384
+ file_menu.addAction(new_wizard_action)
383
385
 
384
386
  file_menu.addSeparator()
385
387
 
386
388
  open_action = QAction(self.tr("Open Project..."), self)
387
- open_action.triggered.connect(self.open_project)
389
+ # [v3.2.1 fix] lambda: avoid passing triggered(bool) as filepath
390
+ open_action.triggered.connect(lambda: self.open_project())
388
391
  file_menu.addAction(open_action)
389
392
 
390
393
  save_action = QAction(self.tr("Save Project..."), self)
@@ -516,7 +519,12 @@ class MainWindow(QMainWindow):
516
519
  self._restart_in_progress = True
517
520
 
518
521
  exe = _sys.executable
519
- args = [exe, "-m", "statable"]
522
+ # [v3.2] Frozen (PyInstaller) support: sys.executable is the
523
+ # bundled StaTable.exe, which does not accept "-m statable".
524
+ if getattr(_sys, "frozen", False):
525
+ args = [exe]
526
+ else:
527
+ args = [exe, "-m", "statable"]
520
528
  cwd = os.getcwd()
521
529
 
522
530
  # Disable UI to avoid double-clicks
@@ -805,8 +813,12 @@ class MainWindow(QMainWindow):
805
813
  f"Failed to save project:\n{e}")
806
814
  return False
807
815
 
808
- def open_project(self):
816
+ def open_project(self, filepath: str = None):
809
817
  """Load the whole project"""
818
+ # [v3.2.1 fix] Qt triggered signal passes bool; normalize to None
819
+ if isinstance(filepath, bool):
820
+ filepath = None
821
+
810
822
  # [v2.3] Prompt to save before loading
811
823
  if not self._maybe_save():
812
824
  return
@@ -814,13 +826,14 @@ class MainWindow(QMainWindow):
814
826
  StaTableLogger.debug(
815
827
  "MainWindow.open_project called")
816
828
 
817
- last_dir = self.prefs.last_project_dir
818
- filepath, _ = QFileDialog.getOpenFileName(
819
- self, "Open Project", last_dir,
820
- "XML files (*.xml)")
821
- if not filepath:
822
- StaTableLogger.debug("Open cancelled")
823
- return
829
+ if filepath is None:
830
+ last_dir = self.prefs.last_project_dir
831
+ filepath, _ = QFileDialog.getOpenFileName(
832
+ self, "Open Project", last_dir,
833
+ "XML files (*.xml)")
834
+ if not filepath:
835
+ StaTableLogger.debug("Open cancelled")
836
+ return
824
837
  try:
825
838
  StaTableLogger.debug(
826
839
  f"Calling project_from_xml: {filepath}")
@@ -1297,6 +1310,38 @@ class MainWindow(QMainWindow):
1297
1310
  # New Project feature (v2.3 / F-15)
1298
1311
  # ==================================================================
1299
1312
 
1313
+ def new_project_wizard(self) -> None:
1314
+ """[v3.2] Launch the New Project Wizard."""
1315
+ if not self._maybe_save():
1316
+ return
1317
+ try:
1318
+ from statable_gui.new_project_wizard import NewProjectWizard
1319
+ except ImportError as e:
1320
+ QMessageBox.critical(
1321
+ self, "Wizard Error",
1322
+ f"Failed to import wizard module:\n{e}")
1323
+ return
1324
+ try:
1325
+ wiz = NewProjectWizard(self)
1326
+ if wiz.exec() != QDialog.Accepted:
1327
+ StaTableLogger.debug("New project wizard: cancelled")
1328
+ return
1329
+ xml_path = wiz.generate()
1330
+ if not xml_path:
1331
+ StaTableLogger.warning("Wizard returned no path")
1332
+ return
1333
+ StaTableLogger.info(f"New project generated: {xml_path}")
1334
+ self.open_project(filepath=xml_path)
1335
+ self.statusBar().showMessage(
1336
+ f"New project created: {xml_path}", 5000)
1337
+ except Exception as e:
1338
+ StaTableLogger.error(f"New project wizard failed: {e!r}")
1339
+ import traceback
1340
+ QMessageBox.critical(
1341
+ self, "Wizard Error",
1342
+ f"Failed to create project:\n{e}\n\n"
1343
+ f"{traceback.format_exc()}")
1344
+
1300
1345
  def new_project(self) -> None:
1301
1346
  """Start a new empty project.
1302
1347
 
@@ -0,0 +1,133 @@
1
+ # statable_gui/new_project_templates.py
2
+ """Template definitions for the New Project Wizard."""
3
+
4
+ from __future__ import annotations
5
+
6
+ # Common events used across all layers
7
+ COMMON_EVENTS = [
8
+ {"name": "EV_INIT", "delivery": "queue", "kind": "signal", "description": "Initialization request"},
9
+ {"name": "EV_START", "delivery": "direct", "kind": "signal", "description": "Start request"},
10
+ {"name": "EV_STOP", "delivery": "direct", "kind": "signal", "description": "Stop request"},
11
+ {"name": "EV_ERROR", "delivery": "queue", "kind": "signal", "description": "Error notification"},
12
+ {"name": "EV_TIMEOUT", "delivery": "queue", "kind": "time", "description": "Timer expiry"},
13
+ ]
14
+
15
+ # Global interrupts (shared across layers)
16
+ INTERRUPTS = [
17
+ {"name": "ISR_TIMER0", "description": "System tick timer"},
18
+ {"name": "ISR_UART_RX", "description": "UART receive complete"},
19
+ {"name": "ISR_UART_TX", "description": "UART transmit complete"},
20
+ {"name": "ISR_GPIO", "description": "GPIO edge detection"},
21
+ {"name": "ISR_ADC", "description": "ADC conversion complete"},
22
+ ]
23
+
24
+ # Global variables (shared)
25
+ GLOBAL_VARIABLES = [
26
+ {"name": "g_counter", "type": "uint32_t", "description": "Loop counter"},
27
+ {"name": "g_error_code", "type": "int32_t", "description": "Last error code"},
28
+ {"name": "g_last_event", "type": "uint16_t", "description": "Last processed event ID"},
29
+ {"name": "g_timeout_ms", "type": "uint32_t", "description": "Timeout in milliseconds"},
30
+ {"name": "g_debug_level", "type": "uint8_t", "description": "Debug verbosity level"},
31
+ ]
32
+
33
+ # Event flags (shared)
34
+ EVENT_FLAGS = [
35
+ {"name": "f_init_done", "description": "Initialization complete"},
36
+ {"name": "f_error", "description": "Error state active"},
37
+ {"name": "f_ready", "description": "Ready for operation"},
38
+ {"name": "f_busy", "description": "Operation in progress"},
39
+ {"name": "f_timeout", "description": "Timeout occurred"},
40
+ ]
41
+
42
+ # Event queues (one per layer + 2 shared)
43
+ EVENT_QUEUES = [
44
+ {"name": "q_driver", "size": 16, "description": "Driver layer event queue"},
45
+ {"name": "q_middleware", "size": 16, "description": "Middleware layer event queue"},
46
+ {"name": "q_application", "size": 16, "description": "Application layer event queue"},
47
+ {"name": "q_system", "size": 32, "description": "System-wide event queue"},
48
+ {"name": "q_debug", "size": 8, "description": "Debug message queue"},
49
+ ]
50
+
51
+
52
+ # Layer templates
53
+ LAYERS_3LAYER = [
54
+ {
55
+ "name": "Driver",
56
+ "priority": 1,
57
+ "description": "Hardware abstraction layer",
58
+ "states": [
59
+ {"name": "Driver_Init", "type": "initial", "description": "Hardware initialization"},
60
+ {"name": "Driver_Idle", "type": "normal", "description": "Waiting for commands"},
61
+ {"name": "Driver_Active", "type": "normal", "description": "Hardware active"},
62
+ {"name": "Driver_Error", "type": "normal", "description": "Hardware error"},
63
+ {"name": "Driver_Recover", "type": "normal", "description": "Recovery in progress"},
64
+ ],
65
+ "role_functions": [
66
+ {"name": "Driver_HwInit", "description": "Initialize hardware"},
67
+ {"name": "Driver_Start", "description": "Start hardware operation"},
68
+ {"name": "Driver_Stop", "description": "Stop hardware operation"},
69
+ {"name": "Driver_HandleError", "description": "Handle hardware error"},
70
+ {"name": "Driver_Cleanup", "description": "Cleanup resources"},
71
+ ],
72
+ },
73
+ {
74
+ "name": "Middleware",
75
+ "priority": 3,
76
+ "description": "Business logic layer",
77
+ "states": [
78
+ {"name": "Middleware_Init", "type": "initial", "description": "Middleware initialization"},
79
+ {"name": "Middleware_Standby", "type": "normal", "description": "Waiting"},
80
+ {"name": "Middleware_Processing","type": "normal", "description": "Processing data"},
81
+ {"name": "Middleware_Waiting", "type": "normal", "description": "Waiting for response"},
82
+ {"name": "Middleware_Error", "type": "normal", "description": "Middleware error"},
83
+ ],
84
+ "role_functions": [
85
+ {"name": "Middleware_Init", "description": "Initialize middleware"},
86
+ {"name": "Middleware_Process", "description": "Process request"},
87
+ {"name": "Middleware_Commit", "description": "Commit result"},
88
+ {"name": "Middleware_Rollback", "description": "Rollback on error"},
89
+ {"name": "Middleware_Cleanup", "description": "Cleanup resources"},
90
+ ],
91
+ },
92
+ {
93
+ "name": "Application",
94
+ "priority": 5,
95
+ "description": "User-facing application layer",
96
+ "states": [
97
+ {"name": "Application_Boot", "type": "initial", "description": "Boot sequence"},
98
+ {"name": "Application_Ready", "type": "normal", "description": "Ready for user input"},
99
+ {"name": "Application_Running", "type": "normal", "description": "Main operation"},
100
+ {"name": "Application_Paused", "type": "normal", "description": "Paused state"},
101
+ {"name": "Application_Shutdown", "type": "normal", "description": "Shutdown sequence"},
102
+ ],
103
+ "role_functions": [
104
+ {"name": "Application_Init", "description": "Initialize application"},
105
+ {"name": "Application_Start", "description": "Start main operation"},
106
+ {"name": "Application_Pause", "description": "Pause operation"},
107
+ {"name": "Application_Resume", "description": "Resume operation"},
108
+ {"name": "Application_Shutdown", "description": "Shutdown application"},
109
+ ],
110
+ },
111
+ ]
112
+
113
+
114
+ TEMPLATES = {
115
+ "blank": {
116
+ "id": "blank",
117
+ "name": "Empty Project",
118
+ "description": "One empty Application layer (existing behavior)",
119
+ "layers": [],
120
+ },
121
+ "basic": {
122
+ "id": "basic",
123
+ "name": "Basic (Single Layer)",
124
+ "description": "Application layer with 5 states + 5 events + 5 role functions",
125
+ "layers": [LAYERS_3LAYER[2]], # Application only
126
+ },
127
+ "three_layer": {
128
+ "id": "three_layer",
129
+ "name": "3-Layer (Driver / Middleware / Application) [Recommended]",
130
+ "description": "Full 3-layer structure with all placeholders",
131
+ "layers": LAYERS_3LAYER,
132
+ },
133
+ }