MoleditPy 2.3.0__py3-none-any.whl → 2.3.2__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.
- moleditpy/modules/constants.py +1 -1
- moleditpy/modules/main_window_main_init.py +38 -19
- moleditpy/modules/main_window_ui_manager.py +2 -6
- moleditpy/modules/plugin_interface.py +4 -12
- moleditpy/modules/plugin_manager.py +14 -6
- {moleditpy-2.3.0.dist-info → moleditpy-2.3.2.dist-info}/METADATA +1 -1
- {moleditpy-2.3.0.dist-info → moleditpy-2.3.2.dist-info}/RECORD +11 -11
- {moleditpy-2.3.0.dist-info → moleditpy-2.3.2.dist-info}/WHEEL +0 -0
- {moleditpy-2.3.0.dist-info → moleditpy-2.3.2.dist-info}/entry_points.txt +0 -0
- {moleditpy-2.3.0.dist-info → moleditpy-2.3.2.dist-info}/licenses/LICENSE +0 -0
- {moleditpy-2.3.0.dist-info → moleditpy-2.3.2.dist-info}/top_level.txt +0 -0
moleditpy/modules/constants.py
CHANGED
|
@@ -1452,18 +1452,22 @@ class MainWindowMainInit(object):
|
|
|
1452
1452
|
# 1. Custom Plugin Openers
|
|
1453
1453
|
# 1. Custom Plugin Openers
|
|
1454
1454
|
if ext_with_dot in self.plugin_manager.file_openers:
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1455
|
+
openers = self.plugin_manager.file_openers[ext_with_dot]
|
|
1456
|
+
# Iterate through openers (already sorted by priority)
|
|
1457
|
+
for opener_info in openers:
|
|
1458
|
+
try:
|
|
1459
|
+
callback = opener_info['callback']
|
|
1460
|
+
# Try to call the opener
|
|
1461
|
+
callback(file_path)
|
|
1462
|
+
|
|
1463
|
+
self.current_file_path = file_path
|
|
1464
|
+
self.update_window_title()
|
|
1465
|
+
return # Success
|
|
1466
|
+
except Exception as e:
|
|
1467
|
+
print(f"Plugin opener failed for '{opener_info.get('plugin', 'Unknown')}': {e}")
|
|
1468
|
+
# If this opener fails, try the next one or fall through to default
|
|
1469
|
+
continue
|
|
1470
|
+
|
|
1467
1471
|
|
|
1468
1472
|
if file_ext in ['mol', 'sdf']:
|
|
1469
1473
|
self.load_mol_file_for_3d_viewing(file_path)
|
|
@@ -1969,7 +1973,6 @@ class MainWindowMainInit(object):
|
|
|
1969
1973
|
a.setData(PLUGIN_ACTION_TAG)
|
|
1970
1974
|
menu.addAction(a)
|
|
1971
1975
|
|
|
1972
|
-
# 5. Integrate File Openers into Import Menu
|
|
1973
1976
|
# 5. Integrate File Openers into Import Menu
|
|
1974
1977
|
if hasattr(self, 'import_menu') and self.plugin_manager.file_openers:
|
|
1975
1978
|
# Add separator
|
|
@@ -1978,16 +1981,32 @@ class MainWindowMainInit(object):
|
|
|
1978
1981
|
|
|
1979
1982
|
# Group by Plugin Name
|
|
1980
1983
|
plugin_map = {}
|
|
1981
|
-
for ext,
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1984
|
+
for ext, openers_list in self.plugin_manager.file_openers.items():
|
|
1985
|
+
# Handles potential multiple openers for same extension
|
|
1986
|
+
for info in openers_list:
|
|
1987
|
+
p_name = info.get('plugin', 'Plugin')
|
|
1988
|
+
if p_name not in plugin_map:
|
|
1989
|
+
plugin_map[p_name] = {}
|
|
1990
|
+
# We can only register one callback per plugin per extension in the menu for now.
|
|
1991
|
+
# Since we process them, let's just take the one present (if a plugin registers multiple openers for same ext - weird but ok)
|
|
1992
|
+
plugin_map[p_name][ext] = info['callback']
|
|
1986
1993
|
|
|
1987
|
-
for p_name, ext_map in plugin_map.items():
|
|
1994
|
+
for p_name, ext_map in sorted(plugin_map.items()):
|
|
1988
1995
|
# Create combined label: "Import .ext1/.ext2 (PluginName)..."
|
|
1989
1996
|
extensions = sorted(ext_map.keys())
|
|
1990
1997
|
ext_str = "/".join(extensions)
|
|
1998
|
+
|
|
1999
|
+
# TRUNCATION LOGIC
|
|
2000
|
+
MAX_EXT_LEN = 30
|
|
2001
|
+
if len(ext_str) > MAX_EXT_LEN:
|
|
2002
|
+
# Find last slash within limit
|
|
2003
|
+
cutoff = ext_str.rfind('/', 0, MAX_EXT_LEN)
|
|
2004
|
+
if cutoff != -1:
|
|
2005
|
+
ext_str = ext_str[:cutoff] + "/..."
|
|
2006
|
+
else:
|
|
2007
|
+
# Fallback if first extension is super long (unlikely but safe)
|
|
2008
|
+
ext_str = ext_str[:MAX_EXT_LEN] + "..."
|
|
2009
|
+
|
|
1991
2010
|
label = f"Import {ext_str} ({p_name})..."
|
|
1992
2011
|
|
|
1993
2012
|
# Create combined filter: "PluginName Files (*.ext1 *.ext2)"
|
|
@@ -313,12 +313,8 @@ class MainWindowUiManager(object):
|
|
|
313
313
|
event.acceptProposedAction()
|
|
314
314
|
return
|
|
315
315
|
|
|
316
|
-
# Plugin
|
|
317
|
-
|
|
318
|
-
for ext in self.plugin_manager.file_openers.keys():
|
|
319
|
-
if file_lower.endswith(ext):
|
|
320
|
-
event.acceptProposedAction()
|
|
321
|
-
return
|
|
316
|
+
# 2. Plugin drop handlers (Drop専用ハンドラ)
|
|
317
|
+
# プラグインが「Dropを受け入れる」と明示している場合のみ許可
|
|
322
318
|
|
|
323
319
|
# Plugin drop handlers (accept more liberally for custom logic)
|
|
324
320
|
# A plugin drop handler might handle it, so accept
|
|
@@ -104,7 +104,7 @@ class PluginContext:
|
|
|
104
104
|
"""
|
|
105
105
|
self._manager.register_optimization_method(self._plugin_name, method_name, callback)
|
|
106
106
|
|
|
107
|
-
def register_file_opener(self, extension: str, callback: Callable[[str], None]):
|
|
107
|
+
def register_file_opener(self, extension: str, callback: Callable[[str], None], priority: int = 0):
|
|
108
108
|
"""
|
|
109
109
|
Register a handler for opening a specific file extension.
|
|
110
110
|
|
|
@@ -112,19 +112,11 @@ class PluginContext:
|
|
|
112
112
|
extension: File extension including dot, e.g. ".xyz".
|
|
113
113
|
callback: Function taking (file_path) -> None.
|
|
114
114
|
Should load the file into the main window.
|
|
115
|
+
priority: Higher priority handlers are tried first (default 0).
|
|
115
116
|
"""
|
|
116
|
-
self._manager.register_file_opener(self._plugin_name, extension, callback)
|
|
117
|
+
self._manager.register_file_opener(self._plugin_name, extension, callback, priority)
|
|
118
|
+
|
|
117
119
|
|
|
118
|
-
def register_file_opener(self, extension: str, callback: Callable[[str], None]):
|
|
119
|
-
"""
|
|
120
|
-
Register a handler for opening a specific file extension.
|
|
121
|
-
|
|
122
|
-
Args:
|
|
123
|
-
extension: File extension including dot, e.g. ".xyz".
|
|
124
|
-
callback: Function taking (file_path) -> None.
|
|
125
|
-
Should load the file into the main window.
|
|
126
|
-
"""
|
|
127
|
-
self._manager.register_file_opener(self._plugin_name, extension, callback)
|
|
128
120
|
|
|
129
121
|
def add_analysis_tool(self, label: str, callback: Callable):
|
|
130
122
|
"""
|
|
@@ -46,7 +46,7 @@ class PluginManager:
|
|
|
46
46
|
# Extended Registries (Added to prevent lazy initialization "monkey patching")
|
|
47
47
|
self.export_actions = []
|
|
48
48
|
self.optimization_methods = {}
|
|
49
|
-
self.file_openers = {}
|
|
49
|
+
self.file_openers = {} # ext -> list of {'plugin':..., 'callback':..., 'priority':...}
|
|
50
50
|
self.analysis_tools = []
|
|
51
51
|
self.save_handlers = {}
|
|
52
52
|
self.load_handlers = {}
|
|
@@ -149,7 +149,6 @@ class PluginManager:
|
|
|
149
149
|
dest_path = os.path.join(self.plugin_dir, filename)
|
|
150
150
|
if os.path.exists(dest_path):
|
|
151
151
|
if os.path.isdir(dest_path):
|
|
152
|
-
import shutil
|
|
153
152
|
shutil.rmtree(dest_path)
|
|
154
153
|
shutil.copy2(file_path, dest_path)
|
|
155
154
|
msg = f"Installed {filename}"
|
|
@@ -346,14 +345,23 @@ class PluginManager:
|
|
|
346
345
|
'plugin': plugin_name, 'callback': callback, 'label': method_name
|
|
347
346
|
}
|
|
348
347
|
|
|
349
|
-
def register_file_opener(self, plugin_name, extension, callback):
|
|
348
|
+
def register_file_opener(self, plugin_name, extension, callback, priority=0):
|
|
350
349
|
# Normalize extension to lowercase
|
|
351
350
|
ext = extension.lower()
|
|
352
351
|
if not ext.startswith('.'):
|
|
353
352
|
ext = '.' + ext
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
353
|
+
|
|
354
|
+
if ext not in self.file_openers:
|
|
355
|
+
self.file_openers[ext] = []
|
|
356
|
+
|
|
357
|
+
self.file_openers[ext].append({
|
|
358
|
+
'plugin': plugin_name,
|
|
359
|
+
'callback': callback,
|
|
360
|
+
'priority': priority
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
# Sort by priority descending
|
|
364
|
+
self.file_openers[ext].sort(key=lambda x: x['priority'], reverse=True)
|
|
357
365
|
|
|
358
366
|
# Analysis Tools registration
|
|
359
367
|
def register_analysis_tool(self, plugin_name, label, callback):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MoleditPy
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.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: GNU GENERAL PUBLIC LICENSE
|
|
@@ -12,7 +12,7 @@ moleditpy/modules/bond_item.py,sha256=eVkEeKvM4igYI67DYxpey3FllqDyt_iWDo4VPYMhaP
|
|
|
12
12
|
moleditpy/modules/bond_length_dialog.py,sha256=6bFPGssnqlgINuqpxLv-OhjMH3_hspnaH8QtorAyu2M,14782
|
|
13
13
|
moleditpy/modules/calculation_worker.py,sha256=KiGQY7i-QCQofEoE0r65KoQgpEGFcbhmxWv6egfkUdc,42324
|
|
14
14
|
moleditpy/modules/color_settings_dialog.py,sha256=Ow44BhCOLo0AFb6klO001k6B4drOgKX9DeNBQhZLp5o,15474
|
|
15
|
-
moleditpy/modules/constants.py,sha256=
|
|
15
|
+
moleditpy/modules/constants.py,sha256=wUyC8vBN2vsqgv6G_qfzdsCX3tOihY0xDCGYB9_B1O0,4702
|
|
16
16
|
moleditpy/modules/constrained_optimization_dialog.py,sha256=REsk4ePsqNmAGPMTS_jckeM7jexrU3krwun8sKqKUCs,30062
|
|
17
17
|
moleditpy/modules/custom_interactor_style.py,sha256=LDNODMJoNHGe1AUSrvqv6PdeJm-hpPmSpWINppnJLt0,38942
|
|
18
18
|
moleditpy/modules/custom_qt_interactor.py,sha256=vCZsDfRO-FtphD5cTP7Ps-5rpHZMIGloaoe6EaKzrsw,4139
|
|
@@ -25,11 +25,11 @@ moleditpy/modules/main_window_dialog_manager.py,sha256=QR96LqHAPSOShXbc9cK-Ffq8a
|
|
|
25
25
|
moleditpy/modules/main_window_edit_3d.py,sha256=CUArB5wcsgq1C7LygAEC6URlbnn4RhRYDa5n-Y-etWI,19731
|
|
26
26
|
moleditpy/modules/main_window_edit_actions.py,sha256=yEc0Nw-VpN0P4e4neUu7pDuUHPGEcu6eFmwWFrSBIQ8,64815
|
|
27
27
|
moleditpy/modules/main_window_export.py,sha256=dSVfylsybDDboDuXU9Inotf6YkrKJwgBTqGYSfq1lRE,38241
|
|
28
|
-
moleditpy/modules/main_window_main_init.py,sha256=
|
|
28
|
+
moleditpy/modules/main_window_main_init.py,sha256=flZEzOH29Z6pplOqku51RMxgKT_QJzsjQK_EheDvjQo,93007
|
|
29
29
|
moleditpy/modules/main_window_molecular_parsers.py,sha256=KR6vzuqc3nutOcorpYr0QOyX3MFBcxTwDhZX96VgJ9Q,48291
|
|
30
30
|
moleditpy/modules/main_window_project_io.py,sha256=TWwtuKDuvgcvPZ9IGmW8r1EJJOrgxrIJRnxe_f4C1oM,17149
|
|
31
31
|
moleditpy/modules/main_window_string_importers.py,sha256=v47wOd4RtjKYcF-aLP-mogGGdYTpTEo3dDyAu79_5MM,10782
|
|
32
|
-
moleditpy/modules/main_window_ui_manager.py,sha256=
|
|
32
|
+
moleditpy/modules/main_window_ui_manager.py,sha256=A-MBoZOq5xHD_Dg9F2BSbBgeWZBY9wDq_7zHacJjKRA,23796
|
|
33
33
|
moleditpy/modules/main_window_view_3d.py,sha256=CxZxyJHl2isF7KtyVWSI9f8LVbvdZM5H9Gnhm_8ovBM,74227
|
|
34
34
|
moleditpy/modules/main_window_view_loaders.py,sha256=gklTMo27QnyJ8Gd0ampPdbm9d0Gi-oHWkIqQuGADHmI,14352
|
|
35
35
|
moleditpy/modules/mirror_dialog.py,sha256=c3v4qY6R4FAljzk4EPaDjL9ZdZMjLQSFLqDMXz2fBUk,4696
|
|
@@ -38,8 +38,8 @@ moleditpy/modules/molecule_scene.py,sha256=khdt7h9Mk_D1cMbYeHGtq7P9aFXo0xG-hcShU
|
|
|
38
38
|
moleditpy/modules/move_group_dialog.py,sha256=Fyuy3Uq1KsFsk9qR96r_FxPbAM_-zSfW2dsMQGv7btc,27276
|
|
39
39
|
moleditpy/modules/periodic_table_dialog.py,sha256=ItEZUts1XCietz9paY-spvbzxh6SXak3GnikwqkHZCw,4006
|
|
40
40
|
moleditpy/modules/planarize_dialog.py,sha256=eaqI1MpF35e-VUMpJATt-EtGG5FhcSUlbAenUaFGabY,8593
|
|
41
|
-
moleditpy/modules/plugin_interface.py,sha256=
|
|
42
|
-
moleditpy/modules/plugin_manager.py,sha256=
|
|
41
|
+
moleditpy/modules/plugin_interface.py,sha256=8_keZsQ6pZEVuEviHXZWlLFs8Yt6J83mwApbX1YL7P0,7791
|
|
42
|
+
moleditpy/modules/plugin_manager.py,sha256=4lXv9stNiiqgY2FRdNDzB41jLcOfc0VzAIF88eMYWlY,20369
|
|
43
43
|
moleditpy/modules/plugin_manager_window.py,sha256=b4kEv0DaWHZG76ZaFTOxn6CVtA62_0MpPYYr10ehCtA,12544
|
|
44
44
|
moleditpy/modules/settings_dialog.py,sha256=Nr7yE8UmYRi3VObWvRlrnv0DnjSjmYXbvqryZ02O12k,65348
|
|
45
45
|
moleditpy/modules/template_preview_item.py,sha256=djdq3tz73d_fJGOvai3E-V9Hk9q9ZW7skx7BV59mooA,6556
|
|
@@ -51,9 +51,9 @@ moleditpy/modules/assets/file_icon.ico,sha256=yyVj084A7HuMNbV073cE_Ag3Ne405qgOP3
|
|
|
51
51
|
moleditpy/modules/assets/icon.icns,sha256=wD5R6-Vw7K662tVKhu2E1ImN0oUuyAP4youesEQsn9c,139863
|
|
52
52
|
moleditpy/modules/assets/icon.ico,sha256=RfgFcx7-dHY_2STdsOQCQziY5SNhDr3gPnjO6jzEDPI,147975
|
|
53
53
|
moleditpy/modules/assets/icon.png,sha256=kCFN1WacYIdy0GN6SFEbNA00ef39pCczBnFdkkBI8Bs,147110
|
|
54
|
-
moleditpy-2.3.
|
|
55
|
-
moleditpy-2.3.
|
|
56
|
-
moleditpy-2.3.
|
|
57
|
-
moleditpy-2.3.
|
|
58
|
-
moleditpy-2.3.
|
|
59
|
-
moleditpy-2.3.
|
|
54
|
+
moleditpy-2.3.2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
55
|
+
moleditpy-2.3.2.dist-info/METADATA,sha256=tEoGUryE-8GZy8pp44lJg1ClxwIywx5xmo9tNEq-tmw,60629
|
|
56
|
+
moleditpy-2.3.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
57
|
+
moleditpy-2.3.2.dist-info/entry_points.txt,sha256=yH1h9JjALhok1foXT3-hYrC4ufoZt8b7oiBcsdnGNNM,54
|
|
58
|
+
moleditpy-2.3.2.dist-info/top_level.txt,sha256=ARICrS4ihlPXqywlKl6o-oJa3Qz3gZRWu_VZsQ3_c44,10
|
|
59
|
+
moleditpy-2.3.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|