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,151 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: statable
|
|
3
|
+
Version: 3.1.0
|
|
4
|
+
Summary: MISRA C:2012-aware state machine design and C code generation for embedded systems
|
|
5
|
+
Author: Hideki Akashi
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/akashi-hideki/StaTable
|
|
8
|
+
Project-URL: Repository, https://github.com/akashi-hideki/StaTable
|
|
9
|
+
Project-URL: Issues, https://github.com/akashi-hideki/StaTable/issues
|
|
10
|
+
Keywords: state machine,MISRA,embedded,code generation,C
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
19
|
+
Classifier: Topic :: Software Development :: Embedded Systems
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Provides-Extra: gui
|
|
23
|
+
Requires-Dist: PySide6>=6.0; extra == "gui"
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
26
|
+
Requires-Dist: pycparser; extra == "dev"
|
|
27
|
+
|
|
28
|
+
# StaTable
|
|
29
|
+
|
|
30
|
+
**MISRA C:2012-aware state machine design and C code generation for embedded systems.**
|
|
31
|
+
|
|
32
|
+
[](https://github.com/akashi-hideki/StaTable/blob/main/LICENSE)
|
|
33
|
+
[](https://www.python.org/)
|
|
34
|
+
[](https://github.com/akashi-hideki/StaTable)
|
|
35
|
+
[](https://www.misra.org.uk/)
|
|
36
|
+
|
|
37
|
+
StaTable is a Python-based tool for designing state machines and
|
|
38
|
+
generating **MISRA C:2012-compliant C code** for embedded systems.
|
|
39
|
+
It provides a CLI, a Python SDK, and a PySide6 GUI.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
- **MISRA C:2012-aware C code generation** — validated with `cppcheck` + official MISRA addon
|
|
46
|
+
- **Multi-layer state machines** — Driver / Middleware / Application with priority execution
|
|
47
|
+
- **State actions (Entry / Exit / Do)** — table-driven dispatch with user-code markers
|
|
48
|
+
- **35 validation rules** across 11 categories with AI-assisted diagnostics
|
|
49
|
+
- **Marker-based user code preservation** — regenerate without losing your custom code
|
|
50
|
+
- **CLI + SDK + GUI** — integrate into any workflow
|
|
51
|
+
- **Pure Python** — easy to install and extend
|
|
52
|
+
- **i18n**: English and Simplified Chinese (简体中文)
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Installation
|
|
57
|
+
|
|
58
|
+
**SDK + CLI only:**
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
pip install statable
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**With GUI (PySide6):**
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
pip install "statable[gui]"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Development:**
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
pip install "statable[dev]"
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Quick Start
|
|
79
|
+
|
|
80
|
+
### CLI
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
statable-cli version
|
|
84
|
+
statable-cli generate --xml design.xml --out generated/ --format json
|
|
85
|
+
statable-cli validate --xml design.xml --format json --exit-on-error
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Python SDK
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
from statable import State, Event, Transition, StateMachine, StateType, EventKind
|
|
92
|
+
from statable.global_defs import GlobalDefinitions
|
|
93
|
+
from codegen import CCodeGenerator, CodeGenerationConfig
|
|
94
|
+
|
|
95
|
+
sm = StateMachine()
|
|
96
|
+
sm.add_state(State(name="Idle", type=StateType.INITIAL))
|
|
97
|
+
sm.add_state(State(name="Running"))
|
|
98
|
+
sm.add_event(Event(name="START", kind=EventKind.SIGNAL))
|
|
99
|
+
sm.set_initial("Idle")
|
|
100
|
+
sm.add_transition(Transition(source="Idle", event="START", target="Running"))
|
|
101
|
+
|
|
102
|
+
cfg = CodeGenerationConfig()
|
|
103
|
+
gen = CCodeGenerator(config=cfg)
|
|
104
|
+
files = gen.generate_all_layers([("Application", sm)], GlobalDefinitions())
|
|
105
|
+
gen.save_generated_code(files, "generated/")
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### GUI
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
python -m statable
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Menu: **Language / 语言** → switch between **English** and **简体中文**.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Requirements
|
|
119
|
+
|
|
120
|
+
- Python 3.10 or later
|
|
121
|
+
- PySide6 >= 6.0 (for GUI)
|
|
122
|
+
- pycparser (optional, for advanced parsing)
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Links
|
|
127
|
+
|
|
128
|
+
- **Homepage**: https://github.com/akashi-hideki/StaTable
|
|
129
|
+
- **Documentation**: https://github.com/akashi-hideki/StaTable/blob/main/README.md
|
|
130
|
+
- **Issues**: https://github.com/akashi-hideki/StaTable/issues
|
|
131
|
+
- **Chinese README**: https://github.com/akashi-hideki/StaTable/blob/main/README_zh-CN.md
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## License
|
|
136
|
+
|
|
137
|
+
Apache License 2.0 — free for commercial and personal use.
|
|
138
|
+
|
|
139
|
+
See [LICENSE](https://github.com/akashi-hideki/StaTable/blob/main/LICENSE) for details.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Acknowledgments
|
|
144
|
+
|
|
145
|
+
- [PySide6](https://www.qt.io/qt-for-python) — Qt 6 for Python
|
|
146
|
+
- [cppcheck](https://cppcheck.sourceforge.io/) — static analysis
|
|
147
|
+
- All contributors and users
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
If StaTable helps you, please consider giving it a ⭐ on GitHub.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
codegen/__init__.py,sha256=v-CDFixuTpGGJ_vVSDQ99PluIaeXpWrqpKraYp-6zIM,1013
|
|
2
|
+
codegen/c_code_generator.py,sha256=ivBce808B7QsxymPI9PhMmgh1vIRMA5dvZVxl-r1V_o,70764
|
|
3
|
+
codegen/code_merger.py,sha256=WZOsOq3e0W4wB4lRo8Hd0yOTIxscARj9UWOkOoRB7cE,13761
|
|
4
|
+
codegen/code_templates.py,sha256=JoWSOSn-9G-72qHbp3fI7fYnZUUlxzhkvi3rOn4D4Qg,20513
|
|
5
|
+
codegen/config.py,sha256=Eux0T-SNVhxXaeca8oi9YTo_2huiVOPfWTDm1o-KgN8,5934
|
|
6
|
+
codegen/enum_generator.py,sha256=7-0np-RX5XfXf3V3RvwbX_rk-2F56J7mAZ6KXE4wdpI,13045
|
|
7
|
+
codegen/event_queue_generator.py,sha256=7fe1BRH-IShuLHL6N4sbm9aBivPS-NCOjlGXeDvvAD4,11746
|
|
8
|
+
codegen/interrupt_generator.py,sha256=xebAzMZ9s7GP7cAvDPuFC70chFSHQog56qBifqLfj9o,13973
|
|
9
|
+
codegen/naming_convention.py,sha256=Agl46ZVlAnadCZSZJi9zpenpJMO0iYfg1xVf_ywrZqY,5226
|
|
10
|
+
codegen/osal_generator.py,sha256=rQIkPZrmic6igXV366v-3rWS9qvlufDNHEn1rL1TWTo,10788
|
|
11
|
+
codegen/role_function_generator.py,sha256=PNwHZxmZfS4doQW7kEMR2IVAxnSdzXHHAx52Scqqlk4,48443
|
|
12
|
+
codegen/sample_data.py,sha256=V0aDFbMRP4BV6cz8Irei-zmhzMJyVqfFvjAviDHzYZE,10465
|
|
13
|
+
codegen/state_actions_generator.py,sha256=OkFOKKHfdwhabF-0_dDY6pQB3F91FjYPEu8980iE-04,15915
|
|
14
|
+
codegen/struct_generator.py,sha256=xlj9myaP-lL6sxKqqfaJxBVG-fLWmA7g6FJKeNU_rNY,30175
|
|
15
|
+
codegen/timer_generator.py,sha256=iOEBwV7vzsSUn8qerbR1rF8qlTzMVOACJbaVrvl1x6Q,11126
|
|
16
|
+
codegen/transition_generator.py,sha256=-Zxle1KVVWVDTtlhxvSlXfWv3ZTzSXFArXdLSgpXI6E,36866
|
|
17
|
+
codegen/type_mapper.py,sha256=gobT9_g6RGeThUd1ScgPpxr4RTb0QdwfdMHm03zr6Zg,2251
|
|
18
|
+
codegen/variable_generator.py,sha256=Xeo9WTdFthfV7IJiBu1h2Z8YxXHdCP24n55PenCZ0ls,16441
|
|
19
|
+
codegen/validate/__init__.py,sha256=s_9FZL3CAwkUKh74BOKmMWXwZPVk45niyl0v5xRT674,1023
|
|
20
|
+
codegen/validate/change_actions.py,sha256=zTvMM2g3x8CUNWpn4fMWuIcTWnnFdxLQMixuZlR9F9I,3068
|
|
21
|
+
codegen/validate/change_applier.py,sha256=bscgXnw3pyxSgr_7vViZ_R1L_P93_5YLNafe_3ny2Ag,17942
|
|
22
|
+
codegen/validate/clipboard_manager.py,sha256=FsgrmfLdR4AED6RSawBw2IOc7fNRL7iJKliwnz-wBVg,1266
|
|
23
|
+
codegen/validate/logger.py,sha256=2kS6hZBX9DX6A7sRgajWzmsCcFEHcoQqIERMyiXGx40,1610
|
|
24
|
+
codegen/validate/models.py,sha256=r2HBsWhcA9h3ikDT25_QVlvMmNGrpv4KACoz08gTskg,5692
|
|
25
|
+
codegen/validate/prompt_generator.py,sha256=_LeUOTtl280boNJmn1YnSmQk1aiSdR1dYMiuMzwEhe8,29766
|
|
26
|
+
codegen/validate/response_parser.py,sha256=YLgPk-77q38LCYVVgqvi5SBxueNUippMgq69VEzFg-Y,5530
|
|
27
|
+
codegen/validate/response_validator.py,sha256=mOuXnONmz4UiO6zdcK0_owRUw1xqftGcSymThc_MvAU,10615
|
|
28
|
+
codegen/validate/validation_dialog.py,sha256=lcwgALR6UxgS0Am6dPBKHUNx6ebejQhJQtsOVkOs4fU,12472
|
|
29
|
+
codegen/validate/validator.py,sha256=I8ZBxScKunw6NGvv9Ub58jJg_L_VmyBaY4PXMyy8nOo,3523
|
|
30
|
+
codegen/validate/data/__init__.py,sha256=NNcxmXtoDcYAnnEctBQRrAaRv2-JXXCwsVqDbebYxnY,649
|
|
31
|
+
codegen/validate/data/action_definitions.py,sha256=Wq6fb5eAmfZ1VtcCwQAicJ10NkzSDYC2LVRkz5Op6k8,9297
|
|
32
|
+
codegen/validate/data/keywords.py,sha256=iCuASfoDxiS-JC6U3AeHKs10SKJNasuE118AUJm979o,1675
|
|
33
|
+
codegen/validate/data/prompt_templates.py,sha256=gF-sxi8cwIVE7isodFaFUY1Ubf99q1_YeWOJe6u1c9Q,5075
|
|
34
|
+
codegen/validate/data/validation_rules.py,sha256=c1g_vb3yhyowhMJuuGaE32DTlPINMeMXHyZ9AN2Gwgc,8183
|
|
35
|
+
codegen/validate/items/__init__.py,sha256=fg4f0XktvE-SZl6syTZjJpHE1CEcqin09n4Y1q-ygG8,969
|
|
36
|
+
codegen/validate/items/base_validator.py,sha256=CwBi0HgfvAohmKM-NHwL3ShN4-0Nm29Xhvf2bxvBYjc,668
|
|
37
|
+
codegen/validate/items/cell_validator.py,sha256=SjYMKN5WX76FogYNnZLmtuvR1t8CtahKbL3O1EV16T4,12188
|
|
38
|
+
codegen/validate/items/custom_type_validator.py,sha256=nirVv9PY69xPj5zosScWjuMgqPMj1mjIdt6Ycg7rE0w,2731
|
|
39
|
+
codegen/validate/items/event_validator.py,sha256=9VH2FXJzqq8Gr69_93lkAfgIxbRVOtgXHhg-ujWUPP0,2889
|
|
40
|
+
codegen/validate/items/flag_validator.py,sha256=OkyzVt7F0J06eVD3hd-PE6c3tkgbPCnPgCVuAGXrv2U,2711
|
|
41
|
+
codegen/validate/items/interrupt_validator.py,sha256=dltTuTSrswgoBq9uxOI5m0ubXmdKaTBegJphmgfNLok,2887
|
|
42
|
+
codegen/validate/items/queue_validator.py,sha256=vhtEVicjyIYukocPHPGoD_Mz4jsIfd9i8rG9CjE4uFI,2760
|
|
43
|
+
codegen/validate/items/role_function_validator.py,sha256=l0lzR0u9Ec-Kb__I-aWQ5j7eYrWAxfmAGPMTuYh8baQ,6963
|
|
44
|
+
codegen/validate/items/state_validator.py,sha256=9ifWpZmT4lxpCur8b95dp7tVBun09Oq8PHyozhAnNAs,3374
|
|
45
|
+
codegen/validate/items/timer_validator.py,sha256=JwYUQvr5HMfjISPBy3-RtbLLh3iGxZLyd4O_9Da1eG8,4946
|
|
46
|
+
codegen/validate/items/transition_validator.py,sha256=AyZeQcS9E34LGbPK1WitAsdvPisOCae6ztad7e0Q6Pw,4339
|
|
47
|
+
codegen/validate/items/variable_validator.py,sha256=JPfCpBJ7LXMLBoOWf9XHOnFjCsFbIXcZaqFGEd7mbCU,4954
|
|
48
|
+
statable/__init__.py,sha256=TUkKfQQvXJQxcvZXTPDQx6rH80oA-safo6iOpAwYMK0,1495
|
|
49
|
+
statable/__main__.py,sha256=cK2t2nNiNgnhMq5k6-ck1uoR1044QGHKz0PbAYQdSMA,1337
|
|
50
|
+
statable/cli.py,sha256=w_3PowggeRHhOvjnk4Ik8FCSCKPO4xy_JSfmVQw-N3o,7279
|
|
51
|
+
statable/global_defs.py,sha256=bZa1w6NnzlEZNdY4JPjgxAN400lYKIzBupOc1AF-jsk,8084
|
|
52
|
+
statable/mermaid_gen.py,sha256=Vciuj9bG1V4x2PhjPr7WeOmTeGgpiaskWOXLcog13to,4746
|
|
53
|
+
statable/model.py,sha256=8PTDipauu2XsW3yNzb7Hoks1cz2Sp0gS1sLuBqFOAbc,15902
|
|
54
|
+
statable/parser.py,sha256=Li6xj49nDENA-OaorTMhVkxQkw6j0ldpq-MyS-ch0tc,2070
|
|
55
|
+
statable/sample_data.py,sha256=kIcSR6_D21ozV7pusutaTq87I5qbJInZKqqHjiB79_g,15773
|
|
56
|
+
statable/state_machine.py,sha256=0zk4jiiFhGYXuSWR4IJEl_e-AlnWEyhx6lQDd2DtK8U,5115
|
|
57
|
+
statable/xml_io.py,sha256=gNSX_WJBmJF-5BQbYp7dfL6LbJGVIEKHmAb8xswHeEU,48684
|
|
58
|
+
statable/shared/__init__.py,sha256=DId1TM2DHfGFFWwpAjN6RaOKf0ssg2Io0yRaBqR8AEo,717
|
|
59
|
+
statable/shared/condition_library.py,sha256=1urybzlFN2IZ8JqwISjnm-6G9P2lgn4vb8qlM7gNaVI,1971
|
|
60
|
+
statable/shared/literal_library.py,sha256=pw9gYTuSrds-g_p3v1ahIa6fLD1_RifHfwMPQMKTq-M,1962
|
|
61
|
+
statable/shared/role_function_library.py,sha256=sg4zD73e3WmWUhq50dyi_EyxHb9-dY2tH4or3h3VZZ0,5272
|
|
62
|
+
statable_gui/__init__.py,sha256=X2WCo34qvm9HyNciQKvWI3q3t5bs7zBFkeV_THQZNPI,703
|
|
63
|
+
statable_gui/action_edit_dialog.py,sha256=DcK1b8qqb6cdScZs0Ut9wtS716zd5eg0R4qV-lw3ufg,9061
|
|
64
|
+
statable_gui/code_generation_dialog.py,sha256=Ps-sXMudxfSolFgeEkYMy6xhmAd5V20b9gmLlKuryXE,17633
|
|
65
|
+
statable_gui/code_generation_settings_dialog.py,sha256=f44LFGx0-HTo5psKqY59hqnX-HRbroh3g5eZLyNJQtc,22161
|
|
66
|
+
statable_gui/common_widgets.py,sha256=lnsSr_rhfpAjSyzl2WuKhH200XRa-2LhJ8lqmtz72bk,21474
|
|
67
|
+
statable_gui/condition_builder_dialog.py,sha256=cTnyp9T62XS4Y6lV3t0t6wV8JqByx1jcIDaxUIoQ3yQ,20429
|
|
68
|
+
statable_gui/condition_edit_dialog.py,sha256=SCAtav-HpmMoy3cqcfDmw1e1lhELYObi0jaZeZ6a-4U,5005
|
|
69
|
+
statable_gui/condition_template_dialog.py,sha256=ivG46siYbz6ndmjX9SVAN2byFmnWke5fe7Y-8vTjcUM,2022
|
|
70
|
+
statable_gui/config.py,sha256=kYnNCJJjzAnDw2Lvv5OX-oYc_ocbC2pa0Gnh8OcN-vw,556
|
|
71
|
+
statable_gui/dialogs.py,sha256=Dt7qA3-Npm-dvW3dveqoxJOCqm3NosprpfuH5Qznx1w,17745
|
|
72
|
+
statable_gui/event_definition_dialog.py,sha256=BkUpekdJ8ysChEhrYDoBHgIS3_XdJOF_s2PcLyaKPDE,26715
|
|
73
|
+
statable_gui/event_delivery_settings_dialog.py,sha256=hapP6fr14W-383DghWpoyf3Dg_WIvNesyOr69eOSsgM,8114
|
|
74
|
+
statable_gui/event_queue_dialog.py,sha256=hM740pthIu4d-Z8H-toZj-hUMZW0X96g35P6I9Ie8A4,10578
|
|
75
|
+
statable_gui/global_defs.py,sha256=vFPQyiY5L5-DaEVupfjTqlw3fr22KTncpJSmECDdQ2o,4951
|
|
76
|
+
statable_gui/global_defs_dialog.py,sha256=JSUE9MP-s3Y6aio6-DNy7nA5EN9jdVR3sdi91NyG6Iw,35377
|
|
77
|
+
statable_gui/interrupt_handler_edit_dialog.py,sha256=nSxSOvfAESYPg3Tt5m99jtxjz4_aDyDnK4LTazKCF5c,34790
|
|
78
|
+
statable_gui/layer_settings_dialog.py,sha256=Zk2pjOUl3KH6R4r4U6T5o4_t3dtllva7DlFblSn-1LY,6056
|
|
79
|
+
statable_gui/literal_definition_dialog.py,sha256=YWQJ8bUYvx6PH18Z7X0cgm_6uNB7IqJscHcIExUENSg,2118
|
|
80
|
+
statable_gui/logger.py,sha256=qB1DmAr6estvJL4qEhT4etoHXrjc8BjFQqcgqVvxVEA,2767
|
|
81
|
+
statable_gui/main_window.py,sha256=PVsLlGL_ZIVB3FsxSERk6Bdp069-8sFrlYyRQxhIcwo,54238
|
|
82
|
+
statable_gui/matrix_table.py,sha256=Dt10xV6M15t-XZJNNrvRD9zaCFSkp9f1tbAi8JUjSss,17047
|
|
83
|
+
statable_gui/preference_keys.py,sha256=F4lCh4gHRsZelpc-y33mDO982KI3dpNk7-1sQq4Flzs,921
|
|
84
|
+
statable_gui/preferences.py,sha256=N7iy6SDfQ49C2kVSmY-QBFC-MlBGK0MXcqDvAeWG9tI,2935
|
|
85
|
+
statable_gui/role_function_dialog.py,sha256=JkqSOolnhAaqzz6NYwnq3KN5JvJlhMx5HMdlr6zGmSM,9264
|
|
86
|
+
statable_gui/sample_data.py,sha256=yj3IQxYBiuAwFA3ycr1AuMMb4FzCKnkS8C8Xfd4iMlc,245
|
|
87
|
+
statable_gui/state_actions_dialog.py,sha256=He7zjgtmDjkTcIFW6XHIuL-fKKq8scUo-ElFH-3xgt8,15496
|
|
88
|
+
statable_gui/symbol_picker.py,sha256=LOWEWykxH0viujEgf0xlpAfj6xpsdbXnxJr3XHwB_Zo,7229
|
|
89
|
+
statable_gui/traceball.py,sha256=uYZ0PLt1lj6yua_JwdKU0CCsyU2xcaENRq6haW4FhCU,1180
|
|
90
|
+
statable_gui/validation_dialog.py,sha256=ByN75eqOgn5ZmKfypDBGslR5Pl53JAS5UHrNtPL_-Po,11100
|
|
91
|
+
statable_gui/widgets.py,sha256=bYt2UvXJyb3jLfypc_RKBHA9fO5PT7zIS0uhawxTwAs,52321
|
|
92
|
+
statable_gui/i18n/__init__.py,sha256=toNNJHsox5axjPAXU_fA84fZ26bw09Qel39_vFeXYUA,3414
|
|
93
|
+
statable_gui/libcntrl/__init__.py,sha256=bc9tlD4c_CAEGSwxoDbSgLRi1n_gczqYnW9QtqDwkmc,546
|
|
94
|
+
statable_gui/libcntrl/condition_library.py,sha256=dONTfLiB8-DnxrGlUFhaSkYT0T-1UdCfOLFOMMFye_o,401
|
|
95
|
+
statable_gui/libcntrl/literal_library.py,sha256=OgiZfV5wazJxIh4oly5I3LnBZhkoUyX1nwF3ms80cvk,393
|
|
96
|
+
statable_gui/libcntrl/literal_management_dialog.py,sha256=e-VkhWU2MKnTaBhRaZFj_LVs6BxRMJAsMyoGRUMiiSY,6674
|
|
97
|
+
statable_gui/libcntrl/role_function_edit_dialog.py,sha256=lU4SuZr4fiVv_M4XiV5Z_jOolNCn0s0Qzl_Qvqtt_4Q,5556
|
|
98
|
+
statable_gui/libcntrl/role_function_library.py,sha256=00PHBVN7h0eUP5lpgxTB8KgJ-p9ZzZuIb2vRRuqIZ7s,405
|
|
99
|
+
statable_gui/transition_editor_direct/__init__.py,sha256=pwPq5qyQI9_AQkUZZvn59fCbTtgN8MhTFcxWEk38TZ8,330
|
|
100
|
+
statable_gui/transition_editor_direct/actions_tab.py,sha256=IRRrAUYvyFbWikBj2PO9zztnlQiHb4ZonKWV_JoCHNU,34372
|
|
101
|
+
statable_gui/transition_editor_direct/code_widget.py,sha256=ZNr3H-0PgasklItclf7TGoYOgI1kdSXK2U2BmFt0kzM,12796
|
|
102
|
+
statable_gui/transition_editor_direct/coverage_analyzer.py,sha256=QMBE5sS_LoROx6oWJSQGRu-GRMoPh6HTxDRAV8g5xmQ,6019
|
|
103
|
+
statable_gui/transition_editor_direct/dialog.py,sha256=wXwjySg67BMGl-5yHvUspb3PFr7uaBphNT9zCxS31K4,13444
|
|
104
|
+
statable_gui/transition_editor_direct/draft.py,sha256=DLUuZf9nHQH_CeDaBaZiHkCIVeYU34D_EXCiHMBVnW8,9159
|
|
105
|
+
statable_gui/transition_editor_direct/edit_dialogs.py,sha256=6aOAa4cOHdeppv3jodfcK1DLm7Rvy0ak4kMrd3EqjRI,6163
|
|
106
|
+
statable_gui/transition_editor_direct/overview_tab.py,sha256=w26RL1DUaXrF_ZDHixj5N3VaKhT3hDRtZ2moqQqr10s,5844
|
|
107
|
+
statable_gui/transition_editor_direct/palette_widget.py,sha256=w6Potl_2-hxDfLeDfbZ6DQ6eY1wrPGtuk3Hvhfh-HGc,9505
|
|
108
|
+
statable_gui/transition_editor_direct/relations_edit_dialog.py,sha256=hczBpUVE2n4BWfwHr3FBA8NXY1aA2tp5e_ffZ5NZ2rY,6001
|
|
109
|
+
statable_gui/transition_editor_direct/relations_tab.py,sha256=WYU93qprG8UdHtWTpsrs8tMr9glkJPpKMFMyj0BhEB0,8965
|
|
110
|
+
statable_gui/transition_editor_direct/system_global_dialog.py,sha256=YQ_Z46G7pDCkLVyOWX9viBnjk83g6D11skdUUc8_ZYM,1706
|
|
111
|
+
statable_gui/transition_editor_direct/transition_actions_dialog.py,sha256=mY2avGuRSg9_Vo3_S06MZyTSpZSrLebL_U05La8VGHM,4273
|
|
112
|
+
statable_gui/transition_editor_direct/transitions_tab.py,sha256=zhCba9PjVILwHqhouyTTanpNJrzpTNRC4w_o6xLtOSg,24459
|
|
113
|
+
statable-3.1.0.dist-info/METADATA,sha256=DIRUEJXm_OqF1QCAqxiKoWWxhosbgHtw5WUhiRRw9KM,4684
|
|
114
|
+
statable-3.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
115
|
+
statable-3.1.0.dist-info/entry_points.txt,sha256=fxjnfPG_VOU2Zh3FnNQt7A5o0uSYUhCdjB_alIBqYZY,51
|
|
116
|
+
statable-3.1.0.dist-info/top_level.txt,sha256=zbXm27ELYZVhvhikBmmsoQ8oOzbMg0L-ys6Y9PBh_VI,30
|
|
117
|
+
statable-3.1.0.dist-info/RECORD,,
|
statable_gui/__init__.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# statable_gui package
|
|
2
|
+
"""\nStaTable GUI layer\n\n[v1.5 added]\n - Keep re-exports minimal\n - Qt-heavy modules (main_window etc.) should be\n explicitly imported\n"""
|
|
3
|
+
|
|
4
|
+
# Settings / environment
|
|
5
|
+
from .config import WINDOW_WIDTH, WINDOW_HEIGHT
|
|
6
|
+
|
|
7
|
+
# Logger (lightweight)
|
|
8
|
+
try:
|
|
9
|
+
from .logger import StaTableLogger
|
|
10
|
+
except ImportError:
|
|
11
|
+
StaTableLogger = None
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
'WINDOW_WIDTH',
|
|
15
|
+
'WINDOW_HEIGHT',
|
|
16
|
+
'StaTableLogger',
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
# Note:
|
|
20
|
+
# MainWindow / StateMachineTab etc. are not re-exported.
|
|
21
|
+
# Loading before creating the PySide6 QApplication causes errors, so
|
|
22
|
+
# On the caller side, use `from statable_gui.main_window import MainWindow` to
|
|
23
|
+
#Explicitly import it.
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
from PySide6.QtCore import Qt
|
|
2
|
+
from PySide6.QtGui import QFont
|
|
3
|
+
from PySide6.QtWidgets import (
|
|
4
|
+
QDialog, QVBoxLayout, QHBoxLayout, QTextEdit, QComboBox,
|
|
5
|
+
QPushButton, QLabel, QDialogButtonBox, QMessageBox,
|
|
6
|
+
QSplitter, QWidget, QMenu
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
from .role_function_dialog import RoleFunctionDialog
|
|
10
|
+
from .global_defs import GlobalDefinitions
|
|
11
|
+
from .global_defs_dialog import VariableEditDialog, FlagEditDialog
|
|
12
|
+
from .common_widgets import TitleEditWidget
|
|
13
|
+
from .symbol_picker import SymbolPickerWidget
|
|
14
|
+
from .logger import StaTableLogger
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ActionEditDialog(QDialog):
|
|
18
|
+
"""Dialog to edit the action of a transition (H3: qualified_name insertion support)"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, parent=None, action_text="", title="",
|
|
21
|
+
role_functions=None, global_defs=None):
|
|
22
|
+
super().__init__(parent)
|
|
23
|
+
self.setWindowTitle(self.tr("ActionEdit"))
|
|
24
|
+
self.setMinimumSize(900, 650)
|
|
25
|
+
self.role_functions = role_functions if role_functions is not None else {}
|
|
26
|
+
self.global_defs = global_defs if global_defs else GlobalDefinitions()
|
|
27
|
+
|
|
28
|
+
StaTableLogger.debug(
|
|
29
|
+
f"ActionEditDialog.__init__: action_text_len={len(action_text)}, "
|
|
30
|
+
f"title='{title}', roles={len(self.role_functions)}, "
|
|
31
|
+
f"vars={len(self.global_defs.variables)}, "
|
|
32
|
+
f"flags={len(self.global_defs.flags)}"
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
main_layout = QVBoxLayout(self)
|
|
36
|
+
|
|
37
|
+
self.title_widget = TitleEditWidget(self, title=title)
|
|
38
|
+
main_layout.addWidget(self.title_widget)
|
|
39
|
+
|
|
40
|
+
role_bar = QHBoxLayout()
|
|
41
|
+
role_bar.addWidget(QLabel(self.tr("Role function:")))
|
|
42
|
+
self.role_combo = QComboBox()
|
|
43
|
+
self.refresh_role_combo()
|
|
44
|
+
role_bar.addWidget(self.role_combo)
|
|
45
|
+
insert_role_btn = QPushButton(self.tr("Insert"))
|
|
46
|
+
insert_role_btn.clicked.connect(self.insert_role_function)
|
|
47
|
+
role_bar.addWidget(insert_role_btn)
|
|
48
|
+
new_role_btn = QPushButton(self.tr("New role function..."))
|
|
49
|
+
new_role_btn.clicked.connect(self.add_new_role_function)
|
|
50
|
+
role_bar.addWidget(new_role_btn)
|
|
51
|
+
main_layout.addLayout(role_bar)
|
|
52
|
+
|
|
53
|
+
self.signature_label = QLabel(self.tr(""))
|
|
54
|
+
self.signature_label.setFont(QFont("Consolas", 9))
|
|
55
|
+
self.signature_label.setStyleSheet("color: #555;")
|
|
56
|
+
main_layout.addWidget(self.signature_label)
|
|
57
|
+
|
|
58
|
+
splitter = QSplitter(Qt.Horizontal)
|
|
59
|
+
main_layout.addWidget(splitter)
|
|
60
|
+
|
|
61
|
+
self.symbol_picker = SymbolPickerWidget(
|
|
62
|
+
global_defs=self.global_defs,
|
|
63
|
+
role_functions=self.role_functions
|
|
64
|
+
)
|
|
65
|
+
self.symbol_picker.insert_requested.connect(self.insert_symbol)
|
|
66
|
+
splitter.addWidget(self.symbol_picker)
|
|
67
|
+
|
|
68
|
+
right_widget = QWidget()
|
|
69
|
+
right_layout = QVBoxLayout(right_widget)
|
|
70
|
+
right_layout.addWidget(QLabel(self.tr("Action code:")))
|
|
71
|
+
self.action_edit = QTextEdit()
|
|
72
|
+
self.action_edit.setAcceptRichText(False)
|
|
73
|
+
self.action_edit.setPlainText(action_text)
|
|
74
|
+
self.action_edit.setFont(QFont("Consolas", 10))
|
|
75
|
+
self.action_edit.setContextMenuPolicy(Qt.CustomContextMenu)
|
|
76
|
+
self.action_edit.customContextMenuRequested.connect(self.show_action_context_menu)
|
|
77
|
+
right_layout.addWidget(self.action_edit, stretch=1)
|
|
78
|
+
splitter.addWidget(right_widget)
|
|
79
|
+
|
|
80
|
+
buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
|
81
|
+
buttons.accepted.connect(self._on_accept)
|
|
82
|
+
buttons.rejected.connect(self.reject)
|
|
83
|
+
main_layout.addWidget(buttons)
|
|
84
|
+
|
|
85
|
+
self.update_signature_label()
|
|
86
|
+
StaTableLogger.debug("ActionEditDialog.__init__ completed")
|
|
87
|
+
|
|
88
|
+
def refresh_role_combo(self):
|
|
89
|
+
self.role_combo.clear()
|
|
90
|
+
for name in self.role_functions.keys():
|
|
91
|
+
self.role_combo.addItem(name)
|
|
92
|
+
try:
|
|
93
|
+
self.role_combo.currentTextChanged.disconnect(self.update_signature_label)
|
|
94
|
+
except (RuntimeError, TypeError):
|
|
95
|
+
pass
|
|
96
|
+
self.role_combo.currentTextChanged.connect(self.update_signature_label)
|
|
97
|
+
StaTableLogger.debug(f"refresh_role_combo: {len(self.role_functions)} roles")
|
|
98
|
+
|
|
99
|
+
def update_signature_label(self):
|
|
100
|
+
func_name = self.role_combo.currentText()
|
|
101
|
+
if func_name:
|
|
102
|
+
rf = self.role_functions.get(func_name)
|
|
103
|
+
if rf:
|
|
104
|
+
# Prefer displaying qualified_name
|
|
105
|
+
display = getattr(rf, 'qualified_name', rf.name)
|
|
106
|
+
arg1 = getattr(rf, 'arg1_type', '') or ''
|
|
107
|
+
arg1n = getattr(rf, 'arg1_name', '') or ''
|
|
108
|
+
arg2 = getattr(rf, 'arg2_type', '') or ''
|
|
109
|
+
arg2n = getattr(rf, 'arg2_name', '') or ''
|
|
110
|
+
ret = getattr(rf, 'return_type', 'void') or 'void'
|
|
111
|
+
sig = f"{ret} {display}({arg1} {arg1n}, {arg2} {arg2n})"
|
|
112
|
+
self.signature_label.setText(sig)
|
|
113
|
+
return
|
|
114
|
+
self.signature_label.setText(self.tr(""))
|
|
115
|
+
|
|
116
|
+
# change: use qualified_name
|
|
117
|
+
def insert_role_function(self):
|
|
118
|
+
"""\n Insert a role function into the action field\n\n - With namespace: \"Driver.Init\" reference form (no arguments)\n - Without namespace: preserve legacy form \"Sensor_Init(arg1, arg2);\"\n """
|
|
119
|
+
func_name = self.role_combo.currentText()
|
|
120
|
+
StaTableLogger.debug(f"insert_role_function: '{func_name}'")
|
|
121
|
+
if not func_name:
|
|
122
|
+
return
|
|
123
|
+
rf = self.role_functions.get(func_name)
|
|
124
|
+
if not rf:
|
|
125
|
+
return
|
|
126
|
+
|
|
127
|
+
qualified = getattr(rf, 'qualified_name', func_name)
|
|
128
|
+
|
|
129
|
+
if '.' in qualified:
|
|
130
|
+
# Namespace.Name form: insert reference only
|
|
131
|
+
call = qualified
|
|
132
|
+
else:
|
|
133
|
+
# Legacy form: preserve call with args
|
|
134
|
+
arg1 = getattr(rf, 'arg1_name', '') or ''
|
|
135
|
+
arg2 = getattr(rf, 'arg2_name', '') or ''
|
|
136
|
+
call = f"{qualified}({arg1}, {arg2});"
|
|
137
|
+
|
|
138
|
+
self.action_edit.insertPlainText(call + "\n")
|
|
139
|
+
|
|
140
|
+
def add_new_role_function(self):
|
|
141
|
+
StaTableLogger.debug("add_new_role_function called")
|
|
142
|
+
dlg = RoleFunctionDialog(self)
|
|
143
|
+
if dlg.exec() == QDialog.Accepted:
|
|
144
|
+
rf = dlg.get_role_function()
|
|
145
|
+
if rf.name in self.role_functions:
|
|
146
|
+
QMessageBox.warning(
|
|
147
|
+
self,
|
|
148
|
+
self.tr("Warning"),
|
|
149
|
+
self.tr("A role function with the same name already exists."),
|
|
150
|
+
)
|
|
151
|
+
return
|
|
152
|
+
self.role_functions[rf.name] = rf
|
|
153
|
+
self.refresh_role_combo()
|
|
154
|
+
self.update_signature_label()
|
|
155
|
+
|
|
156
|
+
def insert_symbol(self, text: str):
|
|
157
|
+
self.action_edit.insertPlainText(text)
|
|
158
|
+
|
|
159
|
+
def show_action_context_menu(self, pos):
|
|
160
|
+
selected_text = self.action_edit.textCursor().selectedText().strip()
|
|
161
|
+
if not selected_text:
|
|
162
|
+
return
|
|
163
|
+
menu = QMenu(self)
|
|
164
|
+
add_var_action = menu.addAction(
|
|
165
|
+
self.tr("'{0}' as global variable").format(selected_text)
|
|
166
|
+
)
|
|
167
|
+
add_flag_action = menu.addAction(
|
|
168
|
+
self.tr("'{0}' as event flag").format(selected_text)
|
|
169
|
+
)
|
|
170
|
+
chosen = menu.exec(self.action_edit.viewport().mapToGlobal(pos))
|
|
171
|
+
if chosen == add_var_action:
|
|
172
|
+
self.register_selected_as_variable(selected_text)
|
|
173
|
+
elif chosen == add_flag_action:
|
|
174
|
+
self.register_selected_as_flag(selected_text)
|
|
175
|
+
|
|
176
|
+
def register_selected_as_variable(self, name: str):
|
|
177
|
+
dlg = VariableEditDialog(self, groups=self.global_defs.variable_groups())
|
|
178
|
+
dlg.name_edit.setText(name)
|
|
179
|
+
if dlg.exec() == QDialog.Accepted:
|
|
180
|
+
var = dlg.get_variable()
|
|
181
|
+
if not var.name:
|
|
182
|
+
return
|
|
183
|
+
if any(v.name == var.name for v in self.global_defs.variables):
|
|
184
|
+
return
|
|
185
|
+
self.global_defs.variables.append(var)
|
|
186
|
+
self.symbol_picker.refresh_list()
|
|
187
|
+
|
|
188
|
+
def register_selected_as_flag(self, name: str):
|
|
189
|
+
dlg = FlagEditDialog(self, groups=self.global_defs.flag_groups())
|
|
190
|
+
dlg.name_edit.setText(name)
|
|
191
|
+
if dlg.exec() == QDialog.Accepted:
|
|
192
|
+
flag = dlg.get_flag()
|
|
193
|
+
if not flag.name:
|
|
194
|
+
return
|
|
195
|
+
if any(f.name == flag.name for f in self.global_defs.flags):
|
|
196
|
+
return
|
|
197
|
+
self.global_defs.flags.append(flag)
|
|
198
|
+
self.symbol_picker.refresh_list()
|
|
199
|
+
|
|
200
|
+
def _on_accept(self):
|
|
201
|
+
action_text = self.action_edit.toPlainText().strip()
|
|
202
|
+
if action_text:
|
|
203
|
+
first_line = action_text.split('\n')[0].strip()
|
|
204
|
+
auto_title = first_line[:20] + ("..." if len(first_line) > 20 else "")
|
|
205
|
+
else:
|
|
206
|
+
auto_title = self.tr("(untitled action)")
|
|
207
|
+
self.title_widget.ensure_title(auto_title)
|
|
208
|
+
self.accept()
|
|
209
|
+
|
|
210
|
+
def get_action_text(self) -> str:
|
|
211
|
+
return self.action_edit.toPlainText().strip()
|
|
212
|
+
|
|
213
|
+
def get_title(self) -> str:
|
|
214
|
+
return self.title_widget.get_title()
|