moleditpy 5.0.0a2__tar.gz → 5.0.2__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 (98) hide show
  1. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/LICENSING.md +1 -3
  2. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/PKG-INFO +3 -3
  3. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/README.md +2 -2
  4. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/pyproject.toml +1 -1
  5. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/MoleditPy.egg-info/PKG-INFO +3 -3
  6. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/plugins/plugin_interface.py +1 -1
  7. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/compute_logic.py +23 -3
  8. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/main_window_init.py +4 -1
  9. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/plugin_menu_manager.py +1 -0
  10. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/user_template_dialog.py +1 -1
  11. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/view_3d_logic.py +7 -0
  12. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/COPYING +0 -0
  13. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/DISTRIBUTION.md +0 -0
  14. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/LICENSE +0 -0
  15. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/THIRD_PARTY_NOTICES.md +0 -0
  16. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/setup.cfg +0 -0
  17. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/MoleditPy.egg-info/SOURCES.txt +0 -0
  18. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/MoleditPy.egg-info/dependency_links.txt +0 -0
  19. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/MoleditPy.egg-info/entry_points.txt +0 -0
  20. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/MoleditPy.egg-info/requires.txt +0 -0
  21. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/MoleditPy.egg-info/top_level.txt +0 -0
  22. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/__init__.py +0 -0
  23. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/__main__.py +0 -0
  24. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/assets/file_icon.ico +0 -0
  25. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/assets/icon.icns +0 -0
  26. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/assets/icon.ico +0 -0
  27. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/assets/icon.png +0 -0
  28. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/core/__init__.py +0 -0
  29. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/core/mol_geometry.py +0 -0
  30. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/core/molecular_data.py +0 -0
  31. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/core/stereo_check.py +0 -0
  32. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/main.py +0 -0
  33. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/plugins/__init__.py +0 -0
  34. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/plugins/plugin_manager.py +0 -0
  35. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/plugins/plugin_manager_window.py +0 -0
  36. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/__init__.py +0 -0
  37. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/about_dialog.py +0 -0
  38. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/align_plane_dialog.py +0 -0
  39. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/alignment_dialog.py +0 -0
  40. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/analysis_window.py +0 -0
  41. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/angle_dialog.py +0 -0
  42. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/app_state.py +0 -0
  43. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/atom_item.py +0 -0
  44. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/atom_picking.py +0 -0
  45. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/base_picking_dialog.py +0 -0
  46. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/bond_item.py +0 -0
  47. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/bond_length_dialog.py +0 -0
  48. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/calculation_worker.py +0 -0
  49. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/chain_mixin.py +0 -0
  50. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/chirality_warning_dialog.py +0 -0
  51. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/color_settings_dialog.py +0 -0
  52. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/constrained_optimization_dialog.py +0 -0
  53. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/custom_interactor_style.py +0 -0
  54. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/custom_qt_interactor.py +0 -0
  55. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/dialog_3d_picking_mixin.py +0 -0
  56. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/dialog_logic.py +0 -0
  57. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/dihedral_dialog.py +0 -0
  58. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/edit_3d_logic.py +0 -0
  59. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/edit_actions_logic.py +0 -0
  60. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/export_logic.py +0 -0
  61. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/geometry_base_dialog.py +0 -0
  62. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/io_logic.py +0 -0
  63. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/main_window.py +0 -0
  64. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/menu_utils.py +0 -0
  65. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/mirror_dialog.py +0 -0
  66. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/molecular_scene_handler.py +0 -0
  67. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/molecule_scene.py +0 -0
  68. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/move_dialog_mixin.py +0 -0
  69. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/move_group_dialog.py +0 -0
  70. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/move_selected_atoms_dialog.py +0 -0
  71. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/periodic_table_dialog.py +0 -0
  72. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/planarize_dialog.py +0 -0
  73. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/preview_molecule.py +0 -0
  74. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/sdf_record_dialog.py +0 -0
  75. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/settings_dialog.py +0 -0
  76. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/settings_tabs/__init__.py +0 -0
  77. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/settings_tabs/settings_2d_cleanup_tab.py +0 -0
  78. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/settings_tabs/settings_2d_tab.py +0 -0
  79. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/settings_tabs/settings_3d_tabs.py +0 -0
  80. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/settings_tabs/settings_labels_tab.py +0 -0
  81. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/settings_tabs/settings_other_tab.py +0 -0
  82. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/settings_tabs/settings_tab_base.py +0 -0
  83. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/string_importers.py +0 -0
  84. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/template_preview_item.py +0 -0
  85. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/template_preview_view.py +0 -0
  86. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/translation_dialog.py +0 -0
  87. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/ui_manager.py +0 -0
  88. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/ui/zoomable_view.py +0 -0
  89. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/utils/__init__.py +0 -0
  90. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/utils/constants.py +0 -0
  91. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/utils/default_settings.py +0 -0
  92. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/utils/finite_float.py +0 -0
  93. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/utils/hit_radius.py +0 -0
  94. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/utils/label_style.py +0 -0
  95. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/utils/sdf_records.py +0 -0
  96. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/utils/sip_isdeleted_safe.py +0 -0
  97. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/utils/suppress_log.py +0 -0
  98. {moleditpy-5.0.0a2 → moleditpy-5.0.2}/src/moleditpy/utils/system_utils.py +0 -0
@@ -1,11 +1,9 @@
1
1
  # Licensing and independently developed plugins
2
2
 
3
- MoleditPy 5.0.0a1 and later is licensed under the GNU Lesser General Public License, version 3 or (at your option) any later version (LGPL-3.0-or-later). `LICENSE` contains LGPLv3's additional permissions; `COPYING` contains the incorporated GPLv3 terms. Earlier releases keep their original license.
3
+ MoleditPy 5.0.0 and later is licensed under the GNU Lesser General Public License, version 3 or (at your option) any later version (LGPL-3.0-or-later). `LICENSE` contains LGPLv3's additional permissions; `COPYING` contains the incorporated GPLv3 terms. Earlier releases keep their original license.
4
4
 
5
5
  Copyright holder permission: independently developed plugins that use MoleditPy's documented plugin API may be distributed under any license, including proprietary licenses. Their authors choose their license and retain their copyright. This permission does not relicense copied or modified MoleditPy code, or code/libraries belonging to third parties. Those components retain their own licenses and obligations. Existing plugins retain their current licenses unless their authors explicitly change them.
6
6
 
7
7
  Modifications to MoleditPy itself remain subject to the LGPL. Distribution terms must allow users to modify the covered components and reverse engineer for debugging their modifications as required by LGPLv3. No separate activation, signature check, or plugin restriction blocks modified builds.
8
8
 
9
- This migration was authorized by the project owner. The repository attribution audit (`git shortlog -sne`) identifies Hiromichi Yokoyama/HiroYokoyama identities, automation bots, and CodexSandboxOffline under the owner's email. Third-party code is excluded from the relicensing grant.
10
-
11
9
  See [distribution and library replacement instructions](DISTRIBUTION.md) and [third-party notices](THIRD_PARTY_NOTICES.md).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MoleditPy
3
- Version: 5.0.0a2
3
+ Version: 5.0.2
4
4
  Summary: A cross-platform, simple, and intuitive molecular structure editor built in Python. It allows 2D molecular drawing and 3D structure visualization. It supports exporting structure files for input to DFT calculation software.
5
5
  Author-email: HiroYokoyama <titech.yoko.hiro@gmail.com>
6
6
  License-Expression: LGPL-3.0-or-later
@@ -92,6 +92,6 @@ Please also cite the plugins you used; see [Citation in the plugin collection](h
92
92
 
93
93
  ## License & Disclaimer
94
94
 
95
- This project is licensed under the GNU Lesser General Public License v3.0 or later (LGPL-3.0-or-later) - see the [LICENSE](https://github.com/HiroYokoyama/python_molecular_editor/blob/v5.0.0a1/LICENSE) file for details. As open-source software, it is provided 'as is' without warranty of any kind, and the author assumes no responsibility or liability for the results. Although outputs have been carefully verified, users are strongly encouraged to independently check and validate them for critical applications (such as publications). If you encounter any bugs, please open an issue.
95
+ This project is licensed under the GNU Lesser General Public License v3.0 or later (LGPL-3.0-or-later) - see the [LICENSE](https://github.com/HiroYokoyama/python_molecular_editor/blob/main/LICENSE) file for details. As open-source software, it is provided 'as is' without warranty of any kind, and the author assumes no responsibility or liability for the results. Although outputs have been carefully verified, users are strongly encouraged to independently check and validate them for critical applications (such as publications). If you encounter any bugs, please open an issue.
96
96
 
97
- Independently developed plugins may use any license, including proprietary licenses. Existing plugins retain their licenses. See [licensing policy](https://github.com/HiroYokoyama/python_molecular_editor/blob/v5.0.0a1/LICENSING.md) and [binary distribution instructions](https://github.com/HiroYokoyama/python_molecular_editor/blob/v5.0.0a1/DISTRIBUTION.md).
97
+ Independently developed plugins may use any license, including proprietary licenses. Existing plugins retain their licenses. See [licensing policy](https://github.com/HiroYokoyama/python_molecular_editor/blob/main/LICENSING.md) and [binary distribution instructions](https://github.com/HiroYokoyama/python_molecular_editor/blob/main/DISTRIBUTION.md).
@@ -59,6 +59,6 @@ Please also cite the plugins you used; see [Citation in the plugin collection](h
59
59
 
60
60
  ## License & Disclaimer
61
61
 
62
- This project is licensed under the GNU Lesser General Public License v3.0 or later (LGPL-3.0-or-later) - see the [LICENSE](https://github.com/HiroYokoyama/python_molecular_editor/blob/v5.0.0a1/LICENSE) file for details. As open-source software, it is provided 'as is' without warranty of any kind, and the author assumes no responsibility or liability for the results. Although outputs have been carefully verified, users are strongly encouraged to independently check and validate them for critical applications (such as publications). If you encounter any bugs, please open an issue.
62
+ This project is licensed under the GNU Lesser General Public License v3.0 or later (LGPL-3.0-or-later) - see the [LICENSE](https://github.com/HiroYokoyama/python_molecular_editor/blob/main/LICENSE) file for details. As open-source software, it is provided 'as is' without warranty of any kind, and the author assumes no responsibility or liability for the results. Although outputs have been carefully verified, users are strongly encouraged to independently check and validate them for critical applications (such as publications). If you encounter any bugs, please open an issue.
63
63
 
64
- Independently developed plugins may use any license, including proprietary licenses. Existing plugins retain their licenses. See [licensing policy](https://github.com/HiroYokoyama/python_molecular_editor/blob/v5.0.0a1/LICENSING.md) and [binary distribution instructions](https://github.com/HiroYokoyama/python_molecular_editor/blob/v5.0.0a1/DISTRIBUTION.md).
64
+ Independently developed plugins may use any license, including proprietary licenses. Existing plugins retain their licenses. See [licensing policy](https://github.com/HiroYokoyama/python_molecular_editor/blob/main/LICENSING.md) and [binary distribution instructions](https://github.com/HiroYokoyama/python_molecular_editor/blob/main/DISTRIBUTION.md).
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "MoleditPy"
7
7
 
8
- version = "5.0.0a2"
8
+ version = "5.0.2"
9
9
 
10
10
  license = "LGPL-3.0-or-later"
11
11
  license-files = ["LICENSE", "COPYING", "THIRD_PARTY_NOTICES.md", "DISTRIBUTION.md", "LICENSING.md"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MoleditPy
3
- Version: 5.0.0a2
3
+ Version: 5.0.2
4
4
  Summary: A cross-platform, simple, and intuitive molecular structure editor built in Python. It allows 2D molecular drawing and 3D structure visualization. It supports exporting structure files for input to DFT calculation software.
5
5
  Author-email: HiroYokoyama <titech.yoko.hiro@gmail.com>
6
6
  License-Expression: LGPL-3.0-or-later
@@ -92,6 +92,6 @@ Please also cite the plugins you used; see [Citation in the plugin collection](h
92
92
 
93
93
  ## License & Disclaimer
94
94
 
95
- This project is licensed under the GNU Lesser General Public License v3.0 or later (LGPL-3.0-or-later) - see the [LICENSE](https://github.com/HiroYokoyama/python_molecular_editor/blob/v5.0.0a1/LICENSE) file for details. As open-source software, it is provided 'as is' without warranty of any kind, and the author assumes no responsibility or liability for the results. Although outputs have been carefully verified, users are strongly encouraged to independently check and validate them for critical applications (such as publications). If you encounter any bugs, please open an issue.
95
+ This project is licensed under the GNU Lesser General Public License v3.0 or later (LGPL-3.0-or-later) - see the [LICENSE](https://github.com/HiroYokoyama/python_molecular_editor/blob/main/LICENSE) file for details. As open-source software, it is provided 'as is' without warranty of any kind, and the author assumes no responsibility or liability for the results. Although outputs have been carefully verified, users are strongly encouraged to independently check and validate them for critical applications (such as publications). If you encounter any bugs, please open an issue.
96
96
 
97
- Independently developed plugins may use any license, including proprietary licenses. Existing plugins retain their licenses. See [licensing policy](https://github.com/HiroYokoyama/python_molecular_editor/blob/v5.0.0a1/LICENSING.md) and [binary distribution instructions](https://github.com/HiroYokoyama/python_molecular_editor/blob/v5.0.0a1/DISTRIBUTION.md).
97
+ Independently developed plugins may use any license, including proprietary licenses. Existing plugins retain their licenses. See [licensing policy](https://github.com/HiroYokoyama/python_molecular_editor/blob/main/LICENSING.md) and [binary distribution instructions](https://github.com/HiroYokoyama/python_molecular_editor/blob/main/DISTRIBUTION.md).
@@ -65,7 +65,7 @@ class PluginContext:
65
65
  Anything else is ignored, so unknown values stay forward
66
66
  compatible. Added in 4.8.1 — passing it to an older MoleditPy
67
67
  raises TypeError, so guard the call if your plugin supports
68
- both (see PLUGIN_DEVELOPMENT_MANUAL_V4.md).
68
+ both (see PLUGIN_DEVELOPMENT_MANUAL_V5.md).
69
69
  """
70
70
  self._manager.register_menu_action(
71
71
  self._plugin_name, path, callback, text, icon, shortcut, pin
@@ -86,7 +86,9 @@ class _CalculationReceiver(QObject):
86
86
  def cleanup(self) -> None:
87
87
  with suppress_log(ValueError):
88
88
  self.manager._active_calc_threads.remove(self.calculation_thread)
89
- self.manager._calc_receivers.remove(self)
89
+ # The Python reference goes when Qt has deleted the object (see
90
+ # _retain_until_destroyed). Releasing it here would let shiboken
91
+ # delete this receiver inside its own queued slot call.
90
92
  self.deleteLater()
91
93
 
92
94
 
@@ -101,7 +103,8 @@ class ComputeManager:
101
103
  self.host = host
102
104
  self.last_successful_optimization_method: Optional[str] = None
103
105
  self._active_calc_threads: List[QThread] = []
104
- self._calc_receivers: List[_CalculationReceiver] = []
106
+ # id(QObject) -> Python objects kept alive until that QObject is destroyed.
107
+ self._calc_objects: Dict[int, Tuple[Any, ...]] = {}
105
108
  self.halt_ids: Set[int] = set()
106
109
  self.next_conversion_id: int = 1
107
110
  self.active_worker_ids: Set[int] = set()
@@ -590,6 +593,19 @@ class ComputeManager:
590
593
  mol_block, mol, self.host.state_manager.data.bonds
591
594
  )
592
595
 
596
+ def _retain_until_destroyed(self, owner: QObject, *extra: Any) -> None:
597
+ """Keep *owner* (and *extra*) referenced until Qt deletes *owner*.
598
+
599
+ These objects have no Qt parent, so shiboken deletes the C++ object
600
+ as soon as the last Python reference goes. Dropping that reference
601
+ only from ``destroyed`` leaves every deletion to ``deleteLater``.
602
+ """
603
+ key = id(owner)
604
+ self._calc_objects[key] = (owner, *extra)
605
+ owner.destroyed.connect(
606
+ lambda *_args, key=key: self._calc_objects.pop(key, None)
607
+ )
608
+
593
609
  def _start_calculation_worker(
594
610
  self, mol_block: str, options: Dict[str, Any], run_id: int
595
611
  ) -> None:
@@ -604,7 +620,11 @@ class ComputeManager:
604
620
  worker.error.connect(receiver.error)
605
621
  thread.finished.connect(receiver.cleanup)
606
622
  thread.finished.connect(thread.deleteLater)
607
- self._calc_receivers.append(receiver)
623
+ # The worker is deleted on its own thread before ~QThread returns, so
624
+ # it is released with the thread rather than by its own destroyed
625
+ # signal, which would be emitted off the GUI thread.
626
+ self._retain_until_destroyed(thread, worker)
627
+ self._retain_until_destroyed(receiver)
608
628
  thread.start()
609
629
  QTimer.singleShot(10, lambda: worker.start_work.emit(mol_block, options))
610
630
  self._active_calc_threads.append(thread)
@@ -99,6 +99,7 @@ class MainInitManager:
99
99
  self.toolbar_bottom: Any = None
100
100
  self.plugin_toolbar: Optional[QToolBar] = None
101
101
  self.tool_group: Optional[QActionGroup] = None
102
+ self.style_group: Optional[QActionGroup] = None
102
103
  self.other_atom_action: Optional[QAction] = None
103
104
  self.splitter: Optional[QSplitter] = None
104
105
  self.cleanup_button: Optional[QPushButton] = None
@@ -960,7 +961,7 @@ class MainInitManager:
960
961
 
961
962
  style_menu = QMenu(self.host)
962
963
  self.style_button.setMenu(style_menu)
963
- style_group = QActionGroup(self.host)
964
+ self.style_group = style_group = QActionGroup(self.host)
964
965
  style_group.setExclusive(True)
965
966
 
966
967
  for name, key in [
@@ -971,6 +972,7 @@ class MainInitManager:
971
972
  ]:
972
973
  action = QAction(name, self.host)
973
974
  action.setCheckable(True)
975
+ action.setProperty("moleditpy_3d_style", key)
974
976
  if key == "ball_and_stick":
975
977
  action.setChecked(True)
976
978
  action.triggered.connect(
@@ -985,6 +987,7 @@ class MainInitManager:
985
987
  if not any(a.text() == style_name for a in style_menu.actions()):
986
988
  action = QAction(style_name, self.host)
987
989
  action.setCheckable(True)
990
+ action.setProperty("moleditpy_3d_style", style_name)
988
991
  action.triggered.connect(
989
992
  lambda checked=False, s=style_name: (
990
993
  self.host.view_3d_manager.set_3d_style(s)
@@ -463,6 +463,7 @@ class PluginMenuManager:
463
463
  if not any(a.text() == style_name for a in style_menu.actions()):
464
464
  action = QAction(style_name, self._im.host)
465
465
  action.setCheckable(True)
466
+ action.setProperty("moleditpy_3d_style", style_name)
466
467
  action.triggered.connect(
467
468
  lambda checked=False, s=style_name: (
468
469
  self._im.host.view_3d_manager.set_3d_style(s)
@@ -298,7 +298,7 @@ class UserTemplateDialog(QDialog):
298
298
  layout = QVBoxLayout(widget)
299
299
 
300
300
  # Preview graphics - use custom view class for better resize handling
301
- preview_scene = QGraphicsScene()
301
+ preview_scene = QGraphicsScene(widget)
302
302
  preview_view = TemplatePreviewView(preview_scene)
303
303
  preview_view.setFixedSize(160, 140)
304
304
  preview_view.setRenderHint(QPainter.RenderHint.Antialiasing)
@@ -116,6 +116,13 @@ class View3DManager:
116
116
 
117
117
  def set_3d_style(self, style_name: str) -> None:
118
118
  """Set 3D display style and update view"""
119
+ style_button = self.host.init_manager.style_button
120
+ if style_button is not None and style_button.menu() is not None:
121
+ for action in style_button.menu().actions():
122
+ if action.isCheckable():
123
+ action.setChecked(
124
+ action.property("moleditpy_3d_style") == style_name
125
+ )
119
126
  current_stored_style = getattr(self, "current_3d_style", None)
120
127
  if current_stored_style == style_name:
121
128
  return
File without changes
File without changes
File without changes
File without changes