statable 3.1.1__tar.gz → 3.2.0__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.0}/PKG-INFO +1 -1
  2. {statable-3.1.1 → statable-3.2.0}/codegen/__init__.py +1 -1
  3. {statable-3.1.1 → statable-3.2.0}/pyproject.toml +1 -1
  4. {statable-3.1.1 → statable-3.2.0}/statable/__init__.py +1 -1
  5. {statable-3.1.1 → statable-3.2.0}/statable/cli.py +1 -1
  6. {statable-3.1.1 → statable-3.2.0}/statable.egg-info/PKG-INFO +1 -1
  7. {statable-3.1.1 → statable-3.2.0}/statable.egg-info/SOURCES.txt +4 -1
  8. {statable-3.1.1 → statable-3.2.0}/statable_gui/i18n/__init__.py +11 -1
  9. {statable-3.1.1 → statable-3.2.0}/statable_gui/main_window.py +53 -15
  10. statable-3.2.0/statable_gui/new_project_templates.py +133 -0
  11. statable-3.2.0/statable_gui/new_project_wizard.py +551 -0
  12. {statable-3.1.1 → statable-3.2.0}/tests/test_v3_0_s1_packaging.py +9 -9
  13. {statable-3.1.1 → statable-3.2.0}/tests/test_v3_0_s2_public_api.py +4 -4
  14. {statable-3.1.1 → statable-3.2.0}/tests/test_v3_0_s3_cli.py +4 -4
  15. {statable-3.1.1 → statable-3.2.0}/tests/test_v3_0_s4_docs.py +5 -5
  16. statable-3.2.0/tests/test_v3_2_s1_wizard.py +219 -0
  17. {statable-3.1.1 → statable-3.2.0}/README.md +0 -0
  18. {statable-3.1.1 → statable-3.2.0}/codegen/c_code_generator.py +0 -0
  19. {statable-3.1.1 → statable-3.2.0}/codegen/code_merger.py +0 -0
  20. {statable-3.1.1 → statable-3.2.0}/codegen/code_templates.py +0 -0
  21. {statable-3.1.1 → statable-3.2.0}/codegen/config.py +0 -0
  22. {statable-3.1.1 → statable-3.2.0}/codegen/enum_generator.py +0 -0
  23. {statable-3.1.1 → statable-3.2.0}/codegen/event_queue_generator.py +0 -0
  24. {statable-3.1.1 → statable-3.2.0}/codegen/interrupt_generator.py +0 -0
  25. {statable-3.1.1 → statable-3.2.0}/codegen/naming_convention.py +0 -0
  26. {statable-3.1.1 → statable-3.2.0}/codegen/osal_generator.py +0 -0
  27. {statable-3.1.1 → statable-3.2.0}/codegen/role_function_generator.py +0 -0
  28. {statable-3.1.1 → statable-3.2.0}/codegen/sample_data.py +0 -0
  29. {statable-3.1.1 → statable-3.2.0}/codegen/state_actions_generator.py +0 -0
  30. {statable-3.1.1 → statable-3.2.0}/codegen/struct_generator.py +0 -0
  31. {statable-3.1.1 → statable-3.2.0}/codegen/timer_generator.py +0 -0
  32. {statable-3.1.1 → statable-3.2.0}/codegen/transition_generator.py +0 -0
  33. {statable-3.1.1 → statable-3.2.0}/codegen/type_mapper.py +0 -0
  34. {statable-3.1.1 → statable-3.2.0}/codegen/validate/__init__.py +0 -0
  35. {statable-3.1.1 → statable-3.2.0}/codegen/validate/change_actions.py +0 -0
  36. {statable-3.1.1 → statable-3.2.0}/codegen/validate/change_applier.py +0 -0
  37. {statable-3.1.1 → statable-3.2.0}/codegen/validate/clipboard_manager.py +0 -0
  38. {statable-3.1.1 → statable-3.2.0}/codegen/validate/data/__init__.py +0 -0
  39. {statable-3.1.1 → statable-3.2.0}/codegen/validate/data/action_definitions.py +0 -0
  40. {statable-3.1.1 → statable-3.2.0}/codegen/validate/data/keywords.py +0 -0
  41. {statable-3.1.1 → statable-3.2.0}/codegen/validate/data/prompt_templates.py +0 -0
  42. {statable-3.1.1 → statable-3.2.0}/codegen/validate/data/validation_rules.py +0 -0
  43. {statable-3.1.1 → statable-3.2.0}/codegen/validate/items/__init__.py +0 -0
  44. {statable-3.1.1 → statable-3.2.0}/codegen/validate/items/base_validator.py +0 -0
  45. {statable-3.1.1 → statable-3.2.0}/codegen/validate/items/cell_validator.py +0 -0
  46. {statable-3.1.1 → statable-3.2.0}/codegen/validate/items/custom_type_validator.py +0 -0
  47. {statable-3.1.1 → statable-3.2.0}/codegen/validate/items/event_validator.py +0 -0
  48. {statable-3.1.1 → statable-3.2.0}/codegen/validate/items/flag_validator.py +0 -0
  49. {statable-3.1.1 → statable-3.2.0}/codegen/validate/items/interrupt_validator.py +0 -0
  50. {statable-3.1.1 → statable-3.2.0}/codegen/validate/items/queue_validator.py +0 -0
  51. {statable-3.1.1 → statable-3.2.0}/codegen/validate/items/role_function_validator.py +0 -0
  52. {statable-3.1.1 → statable-3.2.0}/codegen/validate/items/state_validator.py +0 -0
  53. {statable-3.1.1 → statable-3.2.0}/codegen/validate/items/timer_validator.py +0 -0
  54. {statable-3.1.1 → statable-3.2.0}/codegen/validate/items/transition_validator.py +0 -0
  55. {statable-3.1.1 → statable-3.2.0}/codegen/validate/items/variable_validator.py +0 -0
  56. {statable-3.1.1 → statable-3.2.0}/codegen/validate/logger.py +0 -0
  57. {statable-3.1.1 → statable-3.2.0}/codegen/validate/models.py +0 -0
  58. {statable-3.1.1 → statable-3.2.0}/codegen/validate/prompt_generator.py +0 -0
  59. {statable-3.1.1 → statable-3.2.0}/codegen/validate/response_parser.py +0 -0
  60. {statable-3.1.1 → statable-3.2.0}/codegen/validate/response_validator.py +0 -0
  61. {statable-3.1.1 → statable-3.2.0}/codegen/validate/validation_dialog.py +0 -0
  62. {statable-3.1.1 → statable-3.2.0}/codegen/validate/validator.py +0 -0
  63. {statable-3.1.1 → statable-3.2.0}/codegen/variable_generator.py +0 -0
  64. {statable-3.1.1 → statable-3.2.0}/setup.cfg +0 -0
  65. {statable-3.1.1 → statable-3.2.0}/statable/__main__.py +0 -0
  66. {statable-3.1.1 → statable-3.2.0}/statable/global_defs.py +0 -0
  67. {statable-3.1.1 → statable-3.2.0}/statable/mermaid_gen.py +0 -0
  68. {statable-3.1.1 → statable-3.2.0}/statable/model.py +0 -0
  69. {statable-3.1.1 → statable-3.2.0}/statable/parser.py +0 -0
  70. {statable-3.1.1 → statable-3.2.0}/statable/sample_data.py +0 -0
  71. {statable-3.1.1 → statable-3.2.0}/statable/shared/__init__.py +0 -0
  72. {statable-3.1.1 → statable-3.2.0}/statable/shared/condition_library.py +0 -0
  73. {statable-3.1.1 → statable-3.2.0}/statable/shared/literal_library.py +0 -0
  74. {statable-3.1.1 → statable-3.2.0}/statable/shared/role_function_library.py +0 -0
  75. {statable-3.1.1 → statable-3.2.0}/statable/state_machine.py +0 -0
  76. {statable-3.1.1 → statable-3.2.0}/statable/xml_io.py +0 -0
  77. {statable-3.1.1 → statable-3.2.0}/statable.egg-info/dependency_links.txt +0 -0
  78. {statable-3.1.1 → statable-3.2.0}/statable.egg-info/entry_points.txt +0 -0
  79. {statable-3.1.1 → statable-3.2.0}/statable.egg-info/requires.txt +0 -0
  80. {statable-3.1.1 → statable-3.2.0}/statable.egg-info/top_level.txt +0 -0
  81. {statable-3.1.1 → statable-3.2.0}/statable_gui/__init__.py +0 -0
  82. {statable-3.1.1 → statable-3.2.0}/statable_gui/action_edit_dialog.py +0 -0
  83. {statable-3.1.1 → statable-3.2.0}/statable_gui/code_generation_dialog.py +0 -0
  84. {statable-3.1.1 → statable-3.2.0}/statable_gui/code_generation_settings_dialog.py +0 -0
  85. {statable-3.1.1 → statable-3.2.0}/statable_gui/common_widgets.py +0 -0
  86. {statable-3.1.1 → statable-3.2.0}/statable_gui/condition_builder_dialog.py +0 -0
  87. {statable-3.1.1 → statable-3.2.0}/statable_gui/condition_edit_dialog.py +0 -0
  88. {statable-3.1.1 → statable-3.2.0}/statable_gui/condition_template_dialog.py +0 -0
  89. {statable-3.1.1 → statable-3.2.0}/statable_gui/config.py +0 -0
  90. {statable-3.1.1 → statable-3.2.0}/statable_gui/dialogs.py +0 -0
  91. {statable-3.1.1 → statable-3.2.0}/statable_gui/event_definition_dialog.py +0 -0
  92. {statable-3.1.1 → statable-3.2.0}/statable_gui/event_delivery_settings_dialog.py +0 -0
  93. {statable-3.1.1 → statable-3.2.0}/statable_gui/event_queue_dialog.py +0 -0
  94. {statable-3.1.1 → statable-3.2.0}/statable_gui/global_defs.py +0 -0
  95. {statable-3.1.1 → statable-3.2.0}/statable_gui/global_defs_dialog.py +0 -0
  96. {statable-3.1.1 → statable-3.2.0}/statable_gui/interrupt_handler_edit_dialog.py +0 -0
  97. {statable-3.1.1 → statable-3.2.0}/statable_gui/layer_settings_dialog.py +0 -0
  98. {statable-3.1.1 → statable-3.2.0}/statable_gui/libcntrl/__init__.py +0 -0
  99. {statable-3.1.1 → statable-3.2.0}/statable_gui/libcntrl/condition_library.py +0 -0
  100. {statable-3.1.1 → statable-3.2.0}/statable_gui/libcntrl/literal_library.py +0 -0
  101. {statable-3.1.1 → statable-3.2.0}/statable_gui/libcntrl/literal_management_dialog.py +0 -0
  102. {statable-3.1.1 → statable-3.2.0}/statable_gui/libcntrl/role_function_edit_dialog.py +0 -0
  103. {statable-3.1.1 → statable-3.2.0}/statable_gui/libcntrl/role_function_library.py +0 -0
  104. {statable-3.1.1 → statable-3.2.0}/statable_gui/literal_definition_dialog.py +0 -0
  105. {statable-3.1.1 → statable-3.2.0}/statable_gui/logger.py +0 -0
  106. {statable-3.1.1 → statable-3.2.0}/statable_gui/matrix_table.py +0 -0
  107. {statable-3.1.1 → statable-3.2.0}/statable_gui/preference_keys.py +0 -0
  108. {statable-3.1.1 → statable-3.2.0}/statable_gui/preferences.py +0 -0
  109. {statable-3.1.1 → statable-3.2.0}/statable_gui/role_function_dialog.py +0 -0
  110. {statable-3.1.1 → statable-3.2.0}/statable_gui/sample_data.py +0 -0
  111. {statable-3.1.1 → statable-3.2.0}/statable_gui/state_actions_dialog.py +0 -0
  112. {statable-3.1.1 → statable-3.2.0}/statable_gui/symbol_picker.py +0 -0
  113. {statable-3.1.1 → statable-3.2.0}/statable_gui/traceball.py +0 -0
  114. {statable-3.1.1 → statable-3.2.0}/statable_gui/transition_editor_direct/__init__.py +0 -0
  115. {statable-3.1.1 → statable-3.2.0}/statable_gui/transition_editor_direct/actions_tab.py +0 -0
  116. {statable-3.1.1 → statable-3.2.0}/statable_gui/transition_editor_direct/code_widget.py +0 -0
  117. {statable-3.1.1 → statable-3.2.0}/statable_gui/transition_editor_direct/coverage_analyzer.py +0 -0
  118. {statable-3.1.1 → statable-3.2.0}/statable_gui/transition_editor_direct/dialog.py +0 -0
  119. {statable-3.1.1 → statable-3.2.0}/statable_gui/transition_editor_direct/draft.py +0 -0
  120. {statable-3.1.1 → statable-3.2.0}/statable_gui/transition_editor_direct/edit_dialogs.py +0 -0
  121. {statable-3.1.1 → statable-3.2.0}/statable_gui/transition_editor_direct/overview_tab.py +0 -0
  122. {statable-3.1.1 → statable-3.2.0}/statable_gui/transition_editor_direct/palette_widget.py +0 -0
  123. {statable-3.1.1 → statable-3.2.0}/statable_gui/transition_editor_direct/relations_edit_dialog.py +0 -0
  124. {statable-3.1.1 → statable-3.2.0}/statable_gui/transition_editor_direct/relations_tab.py +0 -0
  125. {statable-3.1.1 → statable-3.2.0}/statable_gui/transition_editor_direct/system_global_dialog.py +0 -0
  126. {statable-3.1.1 → statable-3.2.0}/statable_gui/transition_editor_direct/transition_actions_dialog.py +0 -0
  127. {statable-3.1.1 → statable-3.2.0}/statable_gui/transition_editor_direct/transitions_tab.py +0 -0
  128. {statable-3.1.1 → statable-3.2.0}/statable_gui/validation_dialog.py +0 -0
  129. {statable-3.1.1 → statable-3.2.0}/statable_gui/widgets.py +0 -0
  130. {statable-3.1.1 → statable-3.2.0}/tests/test_readme_consistency.py +0 -0
  131. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_2_p1.py +0 -0
  132. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_2_p12_10.py +0 -0
  133. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_2_p12_2.py +0 -0
  134. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_2_p12_5.py +0 -0
  135. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_2_p12_6.py +0 -0
  136. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_2_p12_7.py +0 -0
  137. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_2_p12_8.py +0 -0
  138. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_2_p12_9.py +0 -0
  139. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_2_p2.py +0 -0
  140. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_2_p3.py +0 -0
  141. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_2_p4a.py +0 -0
  142. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_2_p4b.py +0 -0
  143. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_3_p1.py +0 -0
  144. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_4_p1_merge.py +0 -0
  145. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_5_p1.py +0 -0
  146. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_5_p10.py +0 -0
  147. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_5_p11.py +0 -0
  148. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_5_p2.py +0 -0
  149. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_5_p3.py +0 -0
  150. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_5_p4.py +0 -0
  151. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_5_p5.py +0 -0
  152. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_5_p6.py +0 -0
  153. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_5_p8.py +0 -0
  154. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_5_p9.py +0 -0
  155. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_6_p1.py +0 -0
  156. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_6_p2.py +0 -0
  157. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_6_p3.py +0 -0
  158. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_7_p3.py +0 -0
  159. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_7_p4.py +0 -0
  160. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_7_p5_validation.py +0 -0
  161. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_8_p1_ai_prompt.py +0 -0
  162. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_8_p2_response_parser.py +0 -0
  163. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_8_p3_response_validator.py +0 -0
  164. {statable-3.1.1 → statable-3.2.0}/tests/test_v2_8_p4_gui_integration.py +0 -0
  165. {statable-3.1.1 → statable-3.2.0}/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.0
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.0"
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.0"
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.0"
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.0"
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.0
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
 
@@ -375,11 +375,11 @@ class MainWindow(QMainWindow):
375
375
 
376
376
  file_menu = menubar.addMenu(self.tr("File"))
377
377
 
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)
378
+ # [v3.2] New Project Wizard (Ctrl+N)
379
+ new_wizard_action = QAction(self.tr("New Project..."), self)
380
+ new_wizard_action.setShortcut("Ctrl+N")
381
+ new_wizard_action.triggered.connect(self.new_project_wizard)
382
+ file_menu.addAction(new_wizard_action)
383
383
 
384
384
  file_menu.addSeparator()
385
385
 
@@ -516,7 +516,12 @@ class MainWindow(QMainWindow):
516
516
  self._restart_in_progress = True
517
517
 
518
518
  exe = _sys.executable
519
- args = [exe, "-m", "statable"]
519
+ # [v3.2] Frozen (PyInstaller) support: sys.executable is the
520
+ # bundled StaTable.exe, which does not accept "-m statable".
521
+ if getattr(_sys, "frozen", False):
522
+ args = [exe]
523
+ else:
524
+ args = [exe, "-m", "statable"]
520
525
  cwd = os.getcwd()
521
526
 
522
527
  # Disable UI to avoid double-clicks
@@ -805,7 +810,7 @@ class MainWindow(QMainWindow):
805
810
  f"Failed to save project:\n{e}")
806
811
  return False
807
812
 
808
- def open_project(self):
813
+ def open_project(self, filepath: str = None):
809
814
  """Load the whole project"""
810
815
  # [v2.3] Prompt to save before loading
811
816
  if not self._maybe_save():
@@ -814,13 +819,14 @@ class MainWindow(QMainWindow):
814
819
  StaTableLogger.debug(
815
820
  "MainWindow.open_project called")
816
821
 
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
822
+ if filepath is None:
823
+ last_dir = self.prefs.last_project_dir
824
+ filepath, _ = QFileDialog.getOpenFileName(
825
+ self, "Open Project", last_dir,
826
+ "XML files (*.xml)")
827
+ if not filepath:
828
+ StaTableLogger.debug("Open cancelled")
829
+ return
824
830
  try:
825
831
  StaTableLogger.debug(
826
832
  f"Calling project_from_xml: {filepath}")
@@ -1297,6 +1303,38 @@ class MainWindow(QMainWindow):
1297
1303
  # New Project feature (v2.3 / F-15)
1298
1304
  # ==================================================================
1299
1305
 
1306
+ def new_project_wizard(self) -> None:
1307
+ """[v3.2] Launch the New Project Wizard."""
1308
+ if not self._maybe_save():
1309
+ return
1310
+ try:
1311
+ from statable_gui.new_project_wizard import NewProjectWizard
1312
+ except ImportError as e:
1313
+ QMessageBox.critical(
1314
+ self, "Wizard Error",
1315
+ f"Failed to import wizard module:\n{e}")
1316
+ return
1317
+ try:
1318
+ wiz = NewProjectWizard(self)
1319
+ if wiz.exec() != QDialog.Accepted:
1320
+ StaTableLogger.debug("New project wizard: cancelled")
1321
+ return
1322
+ xml_path = wiz.generate()
1323
+ if not xml_path:
1324
+ StaTableLogger.warning("Wizard returned no path")
1325
+ return
1326
+ StaTableLogger.info(f"New project generated: {xml_path}")
1327
+ self.open_project(filepath=xml_path)
1328
+ self.statusBar().showMessage(
1329
+ f"New project created: {xml_path}", 5000)
1330
+ except Exception as e:
1331
+ StaTableLogger.error(f"New project wizard failed: {e!r}")
1332
+ import traceback
1333
+ QMessageBox.critical(
1334
+ self, "Wizard Error",
1335
+ f"Failed to create project:\n{e}\n\n"
1336
+ f"{traceback.format_exc()}")
1337
+
1300
1338
  def new_project(self) -> None:
1301
1339
  """Start a new empty project.
1302
1340
 
@@ -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
+ }