MoleditPy-linux 3.0.5__tar.gz → 3.0.6__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.
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/PKG-INFO +1 -1
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/pyproject.toml +1 -1
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/MoleditPy_linux.egg-info/PKG-INFO +1 -1
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/__main__.py +1 -1
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/main.py +60 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/plugins/plugin_manager.py +42 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/plugins/plugin_manager_window.py +2 -38
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/align_plane_dialog.py +0 -2
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/angle_dialog.py +0 -2
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/bond_length_dialog.py +0 -2
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/dialog_3d_picking_mixin.py +26 -3
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/dialog_logic.py +6 -6
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/dihedral_dialog.py +0 -2
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/main_window_init.py +6 -2
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/planarize_dialog.py +0 -1
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/translation_dialog.py +31 -8
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/utils/constants.py +1 -1
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/LICENSE +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/README.md +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/setup.cfg +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/MoleditPy_linux.egg-info/SOURCES.txt +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/MoleditPy_linux.egg-info/dependency_links.txt +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/MoleditPy_linux.egg-info/entry_points.txt +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/MoleditPy_linux.egg-info/requires.txt +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/MoleditPy_linux.egg-info/top_level.txt +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/__init__.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/assets/file_icon.ico +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/assets/icon.icns +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/assets/icon.ico +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/assets/icon.png +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/core/__init__.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/core/mol_geometry.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/core/molecular_data.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/plugins/__init__.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/plugins/plugin_interface.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/__init__.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/about_dialog.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/alignment_dialog.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/analysis_window.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/app_state.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/atom_item.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/base_picking_dialog.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/bond_item.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/calculation_worker.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/color_settings_dialog.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/compute_logic.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/constrained_optimization_dialog.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/custom_interactor_style.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/custom_qt_interactor.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/edit_3d_logic.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/edit_actions_logic.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/export_logic.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/geometry_base_dialog.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/io_logic.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/main_window.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/mirror_dialog.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/molecular_scene_handler.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/molecule_scene.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/move_group_dialog.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/periodic_table_dialog.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/settings_dialog.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/settings_tabs/__init__.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/settings_tabs/settings_2d_tab.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/settings_tabs/settings_3d_tabs.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/settings_tabs/settings_other_tab.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/settings_tabs/settings_tab_base.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/sip_isdeleted_safe.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/string_importers.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/template_preview_item.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/template_preview_view.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/ui_manager.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/user_template_dialog.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/view_3d_logic.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/zoomable_view.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/utils/__init__.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/utils/default_settings.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/utils/sip_isdeleted_safe.py +0 -0
- {moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/utils/system_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MoleditPy-linux
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.6
|
|
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: GNU GENERAL PUBLIC LICENSE
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MoleditPy-linux
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.6
|
|
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: GNU GENERAL PUBLIC LICENSE
|
|
@@ -11,7 +11,7 @@ DOI: 10.5281/zenodo.17268532
|
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
print("-----------------------------------------------------")
|
|
14
|
-
print("MoleditPy
|
|
14
|
+
print("MoleditPy - A Python-based molecular editing software")
|
|
15
15
|
print("-----------------------------------------------------\n")
|
|
16
16
|
|
|
17
17
|
try:
|
|
@@ -80,9 +80,69 @@ def main():
|
|
|
80
80
|
default=False,
|
|
81
81
|
help="Start in safe mode: skip loading all plugins",
|
|
82
82
|
)
|
|
83
|
+
parser.add_argument(
|
|
84
|
+
"--install-plugin",
|
|
85
|
+
metavar="PATH",
|
|
86
|
+
help="Install a plugin from a .py file, .zip, or folder (Headless)",
|
|
87
|
+
)
|
|
83
88
|
# parse_known_args so Qt's own argv flags (e.g. -platform) are passed through
|
|
84
89
|
args, remaining = parser.parse_known_args()
|
|
85
90
|
|
|
91
|
+
# --- Headless Plugin Installation ---
|
|
92
|
+
if args.install_plugin:
|
|
93
|
+
plugin_path = os.path.abspath(args.install_plugin)
|
|
94
|
+
if not os.path.exists(plugin_path):
|
|
95
|
+
print(f"Error: Plugin path not found: {plugin_path}")
|
|
96
|
+
sys.exit(1)
|
|
97
|
+
|
|
98
|
+
try:
|
|
99
|
+
from moleditpy_linux.plugins.plugin_manager import PluginManager
|
|
100
|
+
except ImportError:
|
|
101
|
+
from .plugins.plugin_manager import PluginManager
|
|
102
|
+
|
|
103
|
+
pm = PluginManager()
|
|
104
|
+
sha256 = pm._compute_sha256(plugin_path)
|
|
105
|
+
|
|
106
|
+
# Extract metadata
|
|
107
|
+
metadata_file = plugin_path
|
|
108
|
+
if os.path.isdir(plugin_path):
|
|
109
|
+
init_py = os.path.join(plugin_path, "__init__.py")
|
|
110
|
+
if os.path.exists(init_py):
|
|
111
|
+
metadata_file = init_py
|
|
112
|
+
|
|
113
|
+
info = (
|
|
114
|
+
pm.get_plugin_info_safe(metadata_file)
|
|
115
|
+
if metadata_file.endswith(".py")
|
|
116
|
+
else {}
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
print("\n" + "=" * 40)
|
|
120
|
+
print(" PLUGIN INSTALLATION (HEADLESS)")
|
|
121
|
+
print("=" * 40)
|
|
122
|
+
print(f" Name: {info.get('name', os.path.basename(plugin_path))}")
|
|
123
|
+
print(f" Author: {info.get('author', 'Unknown')}")
|
|
124
|
+
print(f" Version: {info.get('version', 'Unknown')}")
|
|
125
|
+
print(f" Description: {info.get('description', 'No description')}")
|
|
126
|
+
print("-" * 40)
|
|
127
|
+
print(f" Path: {plugin_path}")
|
|
128
|
+
print(f" SHA-256: {sha256}")
|
|
129
|
+
print("=" * 40)
|
|
130
|
+
|
|
131
|
+
confirm = (
|
|
132
|
+
input("\nDo you want to proceed with installation? (y/N): ").strip().lower()
|
|
133
|
+
)
|
|
134
|
+
if confirm == "y":
|
|
135
|
+
success, msg = pm.install_plugin(plugin_path)
|
|
136
|
+
if success:
|
|
137
|
+
print(f"Success: {msg}")
|
|
138
|
+
sys.exit(0)
|
|
139
|
+
else:
|
|
140
|
+
print(f"Error: {msg}")
|
|
141
|
+
sys.exit(1)
|
|
142
|
+
else:
|
|
143
|
+
print("Installation aborted.")
|
|
144
|
+
sys.exit(0)
|
|
145
|
+
|
|
86
146
|
app = QApplication([sys.argv[0]] + remaining)
|
|
87
147
|
window = MainWindow(initial_file=args.file, safe_mode=args.safe)
|
|
88
148
|
window.show()
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/plugins/plugin_manager.py
RENAMED
|
@@ -12,6 +12,7 @@ DOI: 10.5281/zenodo.17268532
|
|
|
12
12
|
|
|
13
13
|
from __future__ import annotations
|
|
14
14
|
import ast
|
|
15
|
+
import hashlib
|
|
15
16
|
import importlib.util
|
|
16
17
|
import logging
|
|
17
18
|
import os
|
|
@@ -32,6 +33,46 @@ except ImportError:
|
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
class PluginManager:
|
|
36
|
+
def _compute_sha256(self, path: str) -> str:
|
|
37
|
+
"""Computes SHA-256 for a file or a directory (concatenated hashes of all files)."""
|
|
38
|
+
if os.path.isfile(path):
|
|
39
|
+
return self._sha256_for_file(path)
|
|
40
|
+
if os.path.isdir(path):
|
|
41
|
+
return self._sha256_for_directory(path)
|
|
42
|
+
return "N/A"
|
|
43
|
+
|
|
44
|
+
def _sha256_for_file(self, path: str) -> str:
|
|
45
|
+
"""Computes SHA-256 for a single file."""
|
|
46
|
+
hasher = hashlib.sha256()
|
|
47
|
+
try:
|
|
48
|
+
with open(path, "rb") as f:
|
|
49
|
+
for chunk in iter(lambda: f.read(8192), b""):
|
|
50
|
+
hasher.update(chunk)
|
|
51
|
+
return hasher.hexdigest()
|
|
52
|
+
except (AttributeError, OSError, RuntimeError, ValueError, TypeError):
|
|
53
|
+
return "N/A"
|
|
54
|
+
|
|
55
|
+
def _sha256_for_directory(self, dir_path: str) -> str:
|
|
56
|
+
"""Computes SHA-256 for a directory by hashing all files in sorted order."""
|
|
57
|
+
hasher = hashlib.sha256()
|
|
58
|
+
try:
|
|
59
|
+
root = os.path.abspath(dir_path)
|
|
60
|
+
for current_root, _dirs, files in os.walk(root):
|
|
61
|
+
rel_root = os.path.relpath(current_root, root)
|
|
62
|
+
for filename in sorted(files):
|
|
63
|
+
file_path = os.path.join(current_root, filename)
|
|
64
|
+
rel_path = os.path.normpath(os.path.join(rel_root, filename))
|
|
65
|
+
# Hash the path to ensure directory structure is captured
|
|
66
|
+
hasher.update(rel_path.encode("utf-8", errors="replace"))
|
|
67
|
+
hasher.update(b"\0")
|
|
68
|
+
with open(file_path, "rb") as f:
|
|
69
|
+
for chunk in iter(lambda: f.read(8192), b""):
|
|
70
|
+
hasher.update(chunk)
|
|
71
|
+
hasher.update(b"\0")
|
|
72
|
+
return hasher.hexdigest()
|
|
73
|
+
except (AttributeError, OSError, RuntimeError, ValueError, TypeError):
|
|
74
|
+
return "N/A"
|
|
75
|
+
|
|
35
76
|
def __init__(self, main_window: Any = None) -> None:
|
|
36
77
|
self.plugin_dir: str = os.path.join(
|
|
37
78
|
os.path.expanduser("~"), ".moleditpy", "plugins"
|
|
@@ -265,6 +306,7 @@ class PluginManager:
|
|
|
265
306
|
parent_name = ".".join(parts[:i])
|
|
266
307
|
if parent_name not in sys.modules:
|
|
267
308
|
import types as _types
|
|
309
|
+
|
|
268
310
|
stub = _types.ModuleType(parent_name)
|
|
269
311
|
stub.__path__ = []
|
|
270
312
|
stub.__package__ = parent_name
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/plugins/plugin_manager_window.py
RENAMED
|
@@ -12,7 +12,7 @@ DOI: 10.5281/zenodo.17268532
|
|
|
12
12
|
|
|
13
13
|
import os
|
|
14
14
|
import shutil
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
|
|
17
17
|
from PyQt6.QtCore import Qt, QUrl
|
|
18
18
|
from PyQt6.QtGui import QDesktopServices, QDragEnterEvent, QDropEvent
|
|
@@ -259,7 +259,7 @@ class PluginManagerWindow(QDialog):
|
|
|
259
259
|
is_folder = True
|
|
260
260
|
|
|
261
261
|
if is_valid:
|
|
262
|
-
sha256_value = self._compute_sha256(file_path)
|
|
262
|
+
sha256_value = self.plugin_manager._compute_sha256(file_path)
|
|
263
263
|
# Extract info and confirm
|
|
264
264
|
info = {
|
|
265
265
|
"name": os.path.basename(file_path),
|
|
@@ -314,39 +314,3 @@ class PluginManagerWindow(QDialog):
|
|
|
314
314
|
summary += "Errors:\n" + "\n".join(errors)
|
|
315
315
|
|
|
316
316
|
QMessageBox.information(self, "Plugin Installation", summary)
|
|
317
|
-
|
|
318
|
-
def _compute_sha256(self, path):
|
|
319
|
-
if os.path.isfile(path):
|
|
320
|
-
return self._sha256_for_file(path)
|
|
321
|
-
if os.path.isdir(path):
|
|
322
|
-
return self._sha256_for_directory(path)
|
|
323
|
-
return "N/A"
|
|
324
|
-
|
|
325
|
-
def _sha256_for_file(self, path):
|
|
326
|
-
hasher = hashlib.sha256()
|
|
327
|
-
try:
|
|
328
|
-
with open(path, "rb") as f:
|
|
329
|
-
for chunk in iter(lambda: f.read(8192), b""):
|
|
330
|
-
hasher.update(chunk)
|
|
331
|
-
return hasher.hexdigest()
|
|
332
|
-
except (AttributeError, OSError, RuntimeError, ValueError, TypeError):
|
|
333
|
-
return "N/A"
|
|
334
|
-
|
|
335
|
-
def _sha256_for_directory(self, dir_path):
|
|
336
|
-
hasher = hashlib.sha256()
|
|
337
|
-
try:
|
|
338
|
-
root = os.path.abspath(dir_path)
|
|
339
|
-
for current_root, _dirs, files in os.walk(root):
|
|
340
|
-
rel_root = os.path.relpath(current_root, root)
|
|
341
|
-
for filename in sorted(files):
|
|
342
|
-
file_path = os.path.join(current_root, filename)
|
|
343
|
-
rel_path = os.path.normpath(os.path.join(rel_root, filename))
|
|
344
|
-
hasher.update(rel_path.encode("utf-8", errors="replace"))
|
|
345
|
-
hasher.update(b"\0")
|
|
346
|
-
with open(file_path, "rb") as f:
|
|
347
|
-
for chunk in iter(lambda: f.read(8192), b""):
|
|
348
|
-
hasher.update(chunk)
|
|
349
|
-
hasher.update(b"\0")
|
|
350
|
-
return hasher.hexdigest()
|
|
351
|
-
except (AttributeError, OSError, RuntimeError, ValueError, TypeError):
|
|
352
|
-
return "N/A"
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/dialog_3d_picking_mixin.py
RENAMED
|
@@ -192,9 +192,14 @@ class Dialog3DPickingMixin:
|
|
|
192
192
|
color : str, optional
|
|
193
193
|
Label colour (default ``'yellow'``).
|
|
194
194
|
"""
|
|
195
|
-
|
|
195
|
+
plotter = self.main_window.view_3d_manager.plotter
|
|
196
|
+
try:
|
|
197
|
+
cam = plotter.camera_position
|
|
198
|
+
except (AttributeError, RuntimeError, TypeError):
|
|
199
|
+
cam = None
|
|
196
200
|
|
|
197
|
-
|
|
201
|
+
pos = self.main_window.view_3d_manager.atom_positions_3d[atom_idx]
|
|
202
|
+
label_actor = plotter.add_point_labels(
|
|
198
203
|
[pos],
|
|
199
204
|
[label_text],
|
|
200
205
|
point_size=20,
|
|
@@ -204,6 +209,12 @@ class Dialog3DPickingMixin:
|
|
|
204
209
|
)
|
|
205
210
|
self.selection_labels.append(label_actor)
|
|
206
211
|
|
|
212
|
+
if cam is not None:
|
|
213
|
+
try:
|
|
214
|
+
plotter.camera_position = cam
|
|
215
|
+
except (AttributeError, RuntimeError, TypeError):
|
|
216
|
+
pass
|
|
217
|
+
|
|
207
218
|
def show_atom_labels_for(self, atoms_and_labels, color="yellow"):
|
|
208
219
|
"""Clear existing labels and add new ones for each *(idx, text)* pair.
|
|
209
220
|
|
|
@@ -214,11 +225,17 @@ class Dialog3DPickingMixin:
|
|
|
214
225
|
color : str, optional
|
|
215
226
|
Label colour (default ``'yellow'``).
|
|
216
227
|
"""
|
|
228
|
+
plotter = self.main_window.view_3d_manager.plotter
|
|
229
|
+
try:
|
|
230
|
+
cam = plotter.camera_position
|
|
231
|
+
except (AttributeError, RuntimeError, TypeError):
|
|
232
|
+
cam = None
|
|
233
|
+
|
|
217
234
|
self.clear_atom_labels()
|
|
218
235
|
|
|
219
236
|
for atom_idx, label_text in atoms_and_labels:
|
|
220
237
|
pos = self.main_window.view_3d_manager.atom_positions_3d[atom_idx]
|
|
221
|
-
label_actor =
|
|
238
|
+
label_actor = plotter.add_point_labels(
|
|
222
239
|
[pos],
|
|
223
240
|
[label_text],
|
|
224
241
|
point_size=20,
|
|
@@ -227,3 +244,9 @@ class Dialog3DPickingMixin:
|
|
|
227
244
|
always_visible=True,
|
|
228
245
|
)
|
|
229
246
|
self.selection_labels.append(label_actor)
|
|
247
|
+
|
|
248
|
+
if cam is not None:
|
|
249
|
+
try:
|
|
250
|
+
plotter.camera_position = cam
|
|
251
|
+
except (AttributeError, RuntimeError, TypeError):
|
|
252
|
+
pass
|
|
@@ -215,14 +215,14 @@ class DialogManager:
|
|
|
215
215
|
|
|
216
216
|
def open_translation_dialog(self):
|
|
217
217
|
"""Open the translation dialog"""
|
|
218
|
+
# Get preselected atoms
|
|
219
|
+
preselected_atoms = self._get_preselected_atoms_3d()
|
|
220
|
+
|
|
218
221
|
# Disable measurement mode
|
|
219
222
|
if self.host.edit_3d_manager.measurement_mode:
|
|
220
223
|
self.host.init_manager.measurement_action.setChecked(False)
|
|
221
224
|
self.host.edit_3d_manager.toggle_measurement_mode(False)
|
|
222
225
|
|
|
223
|
-
# Get preselected atoms
|
|
224
|
-
preselected_atoms = self._get_preselected_atoms_3d()
|
|
225
|
-
|
|
226
226
|
dialog = TranslationDialog(
|
|
227
227
|
self.host.view_3d_manager.current_mol,
|
|
228
228
|
self.host,
|
|
@@ -241,14 +241,14 @@ class DialogManager:
|
|
|
241
241
|
|
|
242
242
|
def open_move_group_dialog(self):
|
|
243
243
|
"""Open Move Group dialog"""
|
|
244
|
+
# Get preselected atoms
|
|
245
|
+
preselected_atoms = self._get_preselected_atoms_3d()
|
|
246
|
+
|
|
244
247
|
# Disable measurement mode
|
|
245
248
|
if self.host.edit_3d_manager.measurement_mode:
|
|
246
249
|
self.host.init_manager.measurement_action.setChecked(False)
|
|
247
250
|
self.host.edit_3d_manager.toggle_measurement_mode(False)
|
|
248
251
|
|
|
249
|
-
# Get preselected atoms
|
|
250
|
-
preselected_atoms = self._get_preselected_atoms_3d()
|
|
251
|
-
|
|
252
252
|
dialog = MoveGroupDialog(
|
|
253
253
|
self.host.view_3d_manager.current_mol,
|
|
254
254
|
self.host,
|
|
@@ -264,7 +264,10 @@ class MainInitManager:
|
|
|
264
264
|
file_ext = ext_with_dot.lstrip(".")
|
|
265
265
|
|
|
266
266
|
# 1. Custom Plugin Openers
|
|
267
|
-
if
|
|
267
|
+
if (
|
|
268
|
+
self.host.plugin_manager
|
|
269
|
+
and ext_with_dot in self.host.plugin_manager.file_openers
|
|
270
|
+
):
|
|
268
271
|
openers = self.host.plugin_manager.file_openers[ext_with_dot]
|
|
269
272
|
# Iterate through openers (already sorted by priority)
|
|
270
273
|
for opener_info in openers:
|
|
@@ -279,7 +282,8 @@ class MainInitManager:
|
|
|
279
282
|
except Exception as e:
|
|
280
283
|
logging.warning(
|
|
281
284
|
"Plugin opener failed for '%s': %s",
|
|
282
|
-
opener_info.get(
|
|
285
|
+
opener_info.get("plugin", "Unknown"),
|
|
286
|
+
e,
|
|
283
287
|
)
|
|
284
288
|
# If this opener fails, try the next one or fall through to default
|
|
285
289
|
continue
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/translation_dialog.py
RENAMED
|
@@ -40,11 +40,20 @@ class TranslationDialog(BasePickingDialog):
|
|
|
40
40
|
if preselected_atoms:
|
|
41
41
|
self.selected_atoms.update(preselected_atoms)
|
|
42
42
|
|
|
43
|
+
self._is_initializing = True
|
|
43
44
|
self.init_ui()
|
|
45
|
+
self._is_initializing = False
|
|
44
46
|
|
|
45
47
|
if self.selected_atoms:
|
|
46
|
-
self.
|
|
48
|
+
self.tabs.blockSignals(True)
|
|
49
|
+
if len(self.selected_atoms) == 1:
|
|
50
|
+
self.tabs.setCurrentIndex(_TAB_ABSOLUTE)
|
|
51
|
+
self._populate_abs_inputs_from_atom(next(iter(self.selected_atoms)))
|
|
52
|
+
else:
|
|
53
|
+
self.tabs.setCurrentIndex(_TAB_DELTA)
|
|
54
|
+
self.tabs.blockSignals(False)
|
|
47
55
|
self.update_display()
|
|
56
|
+
self.show_atom_labels()
|
|
48
57
|
|
|
49
58
|
# ------------------------------------------------------------------
|
|
50
59
|
# UI construction
|
|
@@ -169,6 +178,8 @@ class TranslationDialog(BasePickingDialog):
|
|
|
169
178
|
# ------------------------------------------------------------------
|
|
170
179
|
|
|
171
180
|
def _on_tab_changed(self, index):
|
|
181
|
+
if hasattr(self, "_is_initializing") and self._is_initializing:
|
|
182
|
+
return
|
|
172
183
|
self.selected_atoms.clear()
|
|
173
184
|
self.clear_atom_labels()
|
|
174
185
|
self.update_display()
|
|
@@ -187,23 +198,27 @@ class TranslationDialog(BasePickingDialog):
|
|
|
187
198
|
# Enforce single selection: replace previous atom
|
|
188
199
|
self.selected_atoms = {atom_idx}
|
|
189
200
|
self._populate_abs_inputs_from_atom(atom_idx)
|
|
190
|
-
self.show_atom_labels()
|
|
191
201
|
self.update_display()
|
|
202
|
+
self.show_atom_labels()
|
|
192
203
|
|
|
193
204
|
def _delta_on_atom_picked(self, atom_idx):
|
|
194
205
|
if atom_idx in self.selected_atoms:
|
|
195
206
|
self.selected_atoms.remove(atom_idx)
|
|
196
207
|
else:
|
|
197
208
|
self.selected_atoms.add(atom_idx)
|
|
198
|
-
self.show_atom_labels()
|
|
199
209
|
self.update_display()
|
|
210
|
+
self.show_atom_labels()
|
|
200
211
|
|
|
201
212
|
# ------------------------------------------------------------------
|
|
202
213
|
# Absolute tab helpers
|
|
203
214
|
# ------------------------------------------------------------------
|
|
204
215
|
|
|
205
216
|
def _populate_abs_inputs_from_atom(self, atom_idx):
|
|
206
|
-
pos =
|
|
217
|
+
pos = (
|
|
218
|
+
self.main_window.view_3d_manager.current_mol.GetConformer().GetPositions()[
|
|
219
|
+
atom_idx
|
|
220
|
+
]
|
|
221
|
+
)
|
|
207
222
|
self.abs_x_input.setText(f"{pos[0]:.4f}")
|
|
208
223
|
self.abs_y_input.setText(f"{pos[1]:.4f}")
|
|
209
224
|
self.abs_z_input.setText(f"{pos[2]:.4f}")
|
|
@@ -236,7 +251,9 @@ class TranslationDialog(BasePickingDialog):
|
|
|
236
251
|
ty = float(self.abs_y_input.text())
|
|
237
252
|
tz = float(self.abs_z_input.text())
|
|
238
253
|
except ValueError:
|
|
239
|
-
QMessageBox.warning(
|
|
254
|
+
QMessageBox.warning(
|
|
255
|
+
self, "Warning", "Please enter valid numbers for X, Y, Z."
|
|
256
|
+
)
|
|
240
257
|
return
|
|
241
258
|
|
|
242
259
|
atom_idx = next(iter(self.selected_atoms))
|
|
@@ -291,7 +308,9 @@ class TranslationDialog(BasePickingDialog):
|
|
|
291
308
|
dy = float(self.dy_input.text())
|
|
292
309
|
dz = float(self.dz_input.text())
|
|
293
310
|
except ValueError:
|
|
294
|
-
QMessageBox.warning(
|
|
311
|
+
QMessageBox.warning(
|
|
312
|
+
self, "Warning", "Please enter valid numbers for dx, dy, dz."
|
|
313
|
+
)
|
|
295
314
|
return
|
|
296
315
|
|
|
297
316
|
if dx == 0 and dy == 0 and dz == 0:
|
|
@@ -325,10 +344,14 @@ class TranslationDialog(BasePickingDialog):
|
|
|
325
344
|
self.abs_apply_btn.setEnabled(True)
|
|
326
345
|
else:
|
|
327
346
|
if count == 0:
|
|
328
|
-
self.delta_selection_label.setText(
|
|
347
|
+
self.delta_selection_label.setText(
|
|
348
|
+
"Click atoms to select (minimum 1 required)"
|
|
349
|
+
)
|
|
329
350
|
self.apply_button.setEnabled(False)
|
|
330
351
|
else:
|
|
331
|
-
self.delta_selection_label.setText(
|
|
352
|
+
self.delta_selection_label.setText(
|
|
353
|
+
f"Selected {count} atom{'s' if count != 1 else ''}"
|
|
354
|
+
)
|
|
332
355
|
self.apply_button.setEnabled(True)
|
|
333
356
|
|
|
334
357
|
def show_atom_labels(self):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/MoleditPy_linux.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/MoleditPy_linux.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/plugins/plugin_interface.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/base_picking_dialog.py
RENAMED
|
File without changes
|
|
File without changes
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/calculation_worker.py
RENAMED
|
File without changes
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/color_settings_dialog.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/custom_interactor_style.py
RENAMED
|
File without changes
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/custom_qt_interactor.py
RENAMED
|
File without changes
|
|
File without changes
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/edit_actions_logic.py
RENAMED
|
File without changes
|
|
File without changes
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/geometry_base_dialog.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/molecular_scene_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/periodic_table_dialog.py
RENAMED
|
File without changes
|
|
File without changes
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/settings_tabs/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/sip_isdeleted_safe.py
RENAMED
|
File without changes
|
|
File without changes
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/template_preview_item.py
RENAMED
|
File without changes
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/template_preview_view.py
RENAMED
|
File without changes
|
|
File without changes
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/ui/user_template_dialog.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/utils/default_settings.py
RENAMED
|
File without changes
|
{moleditpy_linux-3.0.5 → moleditpy_linux-3.0.6}/src/moleditpy_linux/utils/sip_isdeleted_safe.py
RENAMED
|
File without changes
|
|
File without changes
|