MoleditPy 2.3.1__py3-none-any.whl → 2.3.3__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_edit_actions.py +4 -0
- moleditpy/modules/main_window_main_init.py +43 -19
- moleditpy/modules/main_window_ui_manager.py +2 -6
- moleditpy/modules/plugin_interface.py +14 -12
- moleditpy/modules/plugin_manager.py +31 -5
- {moleditpy-2.3.1.dist-info → moleditpy-2.3.3.dist-info}/METADATA +1 -1
- {moleditpy-2.3.1.dist-info → moleditpy-2.3.3.dist-info}/RECORD +12 -12
- {moleditpy-2.3.1.dist-info → moleditpy-2.3.3.dist-info}/WHEEL +0 -0
- {moleditpy-2.3.1.dist-info → moleditpy-2.3.3.dist-info}/entry_points.txt +0 -0
- {moleditpy-2.3.1.dist-info → moleditpy-2.3.3.dist-info}/licenses/LICENSE +0 -0
- {moleditpy-2.3.1.dist-info → moleditpy-2.3.3.dist-info}/top_level.txt +0 -0
moleditpy/modules/constants.py
CHANGED
|
@@ -641,6 +641,10 @@ class MainWindowEditActions(object):
|
|
|
641
641
|
# アプリケーションのイベントループを強制的に処理し、画面の再描画を確実に行う
|
|
642
642
|
QApplication.processEvents()
|
|
643
643
|
|
|
644
|
+
# Call plugin document reset handlers
|
|
645
|
+
if hasattr(self, 'plugin_manager') and self.plugin_manager:
|
|
646
|
+
self.plugin_manager.invoke_document_reset_handlers()
|
|
647
|
+
|
|
644
648
|
self.statusBar().showMessage("Cleared all data.")
|
|
645
649
|
|
|
646
650
|
|
|
@@ -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)
|
|
@@ -1847,6 +1851,11 @@ class MainWindowMainInit(object):
|
|
|
1847
1851
|
action_text = text if text else parts[-1]
|
|
1848
1852
|
action = QAction(action_text, self)
|
|
1849
1853
|
action.triggered.connect(callback)
|
|
1854
|
+
|
|
1855
|
+
# Apply shortcut if provided
|
|
1856
|
+
if action_def.get('shortcut'):
|
|
1857
|
+
action.setShortcut(QKeySequence(action_def['shortcut']))
|
|
1858
|
+
|
|
1850
1859
|
action.setData(PLUGIN_ACTION_TAG) # TAG THE ACTION
|
|
1851
1860
|
current_menu.addAction(action)
|
|
1852
1861
|
|
|
@@ -1969,7 +1978,6 @@ class MainWindowMainInit(object):
|
|
|
1969
1978
|
a.setData(PLUGIN_ACTION_TAG)
|
|
1970
1979
|
menu.addAction(a)
|
|
1971
1980
|
|
|
1972
|
-
# 5. Integrate File Openers into Import Menu
|
|
1973
1981
|
# 5. Integrate File Openers into Import Menu
|
|
1974
1982
|
if hasattr(self, 'import_menu') and self.plugin_manager.file_openers:
|
|
1975
1983
|
# Add separator
|
|
@@ -1978,16 +1986,32 @@ class MainWindowMainInit(object):
|
|
|
1978
1986
|
|
|
1979
1987
|
# Group by Plugin Name
|
|
1980
1988
|
plugin_map = {}
|
|
1981
|
-
for ext,
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1989
|
+
for ext, openers_list in self.plugin_manager.file_openers.items():
|
|
1990
|
+
# Handles potential multiple openers for same extension
|
|
1991
|
+
for info in openers_list:
|
|
1992
|
+
p_name = info.get('plugin', 'Plugin')
|
|
1993
|
+
if p_name not in plugin_map:
|
|
1994
|
+
plugin_map[p_name] = {}
|
|
1995
|
+
# We can only register one callback per plugin per extension in the menu for now.
|
|
1996
|
+
# Since we process them, let's just take the one present (if a plugin registers multiple openers for same ext - weird but ok)
|
|
1997
|
+
plugin_map[p_name][ext] = info['callback']
|
|
1986
1998
|
|
|
1987
|
-
for p_name, ext_map in plugin_map.items():
|
|
1999
|
+
for p_name, ext_map in sorted(plugin_map.items()):
|
|
1988
2000
|
# Create combined label: "Import .ext1/.ext2 (PluginName)..."
|
|
1989
2001
|
extensions = sorted(ext_map.keys())
|
|
1990
2002
|
ext_str = "/".join(extensions)
|
|
2003
|
+
|
|
2004
|
+
# TRUNCATION LOGIC
|
|
2005
|
+
MAX_EXT_LEN = 30
|
|
2006
|
+
if len(ext_str) > MAX_EXT_LEN:
|
|
2007
|
+
# Find last slash within limit
|
|
2008
|
+
cutoff = ext_str.rfind('/', 0, MAX_EXT_LEN)
|
|
2009
|
+
if cutoff != -1:
|
|
2010
|
+
ext_str = ext_str[:cutoff] + "/..."
|
|
2011
|
+
else:
|
|
2012
|
+
# Fallback if first extension is super long (unlikely but safe)
|
|
2013
|
+
ext_str = ext_str[:MAX_EXT_LEN] + "..."
|
|
2014
|
+
|
|
1991
2015
|
label = f"Import {ext_str} ({p_name})..."
|
|
1992
2016
|
|
|
1993
2017
|
# 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
|
"""
|
|
@@ -176,6 +168,16 @@ class PluginContext:
|
|
|
176
168
|
"""
|
|
177
169
|
self._manager.register_3d_style(self._plugin_name, style_name, callback)
|
|
178
170
|
|
|
171
|
+
def register_document_reset_handler(self, callback: Callable[[], None]):
|
|
172
|
+
"""
|
|
173
|
+
Register a callback to be called when a new document is created (File→New).
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
callback: Function with no arguments that resets plugin state.
|
|
177
|
+
"""
|
|
178
|
+
self._manager.register_document_reset_handler(self._plugin_name, callback)
|
|
179
|
+
|
|
180
|
+
|
|
179
181
|
|
|
180
182
|
|
|
181
183
|
|
|
@@ -46,11 +46,12 @@ 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 = {}
|
|
53
53
|
self.custom_3d_styles = {} # style_name -> {'plugin': name, 'callback': func}
|
|
54
|
+
self.document_reset_handlers = [] # List of callbacks to call on new document
|
|
54
55
|
|
|
55
56
|
def get_main_window(self):
|
|
56
57
|
return self.main_window
|
|
@@ -182,6 +183,7 @@ class PluginManager:
|
|
|
182
183
|
self.save_handlers = {}
|
|
183
184
|
self.load_handlers = {}
|
|
184
185
|
self.custom_3d_styles = {}
|
|
186
|
+
self.document_reset_handlers = []
|
|
185
187
|
|
|
186
188
|
if not os.path.exists(self.plugin_dir):
|
|
187
189
|
return []
|
|
@@ -345,14 +347,23 @@ class PluginManager:
|
|
|
345
347
|
'plugin': plugin_name, 'callback': callback, 'label': method_name
|
|
346
348
|
}
|
|
347
349
|
|
|
348
|
-
def register_file_opener(self, plugin_name, extension, callback):
|
|
350
|
+
def register_file_opener(self, plugin_name, extension, callback, priority=0):
|
|
349
351
|
# Normalize extension to lowercase
|
|
350
352
|
ext = extension.lower()
|
|
351
353
|
if not ext.startswith('.'):
|
|
352
354
|
ext = '.' + ext
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
355
|
+
|
|
356
|
+
if ext not in self.file_openers:
|
|
357
|
+
self.file_openers[ext] = []
|
|
358
|
+
|
|
359
|
+
self.file_openers[ext].append({
|
|
360
|
+
'plugin': plugin_name,
|
|
361
|
+
'callback': callback,
|
|
362
|
+
'priority': priority
|
|
363
|
+
})
|
|
364
|
+
|
|
365
|
+
# Sort by priority descending
|
|
366
|
+
self.file_openers[ext].sort(key=lambda x: x['priority'], reverse=True)
|
|
356
367
|
|
|
357
368
|
# Analysis Tools registration
|
|
358
369
|
def register_analysis_tool(self, plugin_name, label, callback):
|
|
@@ -369,6 +380,21 @@ class PluginManager:
|
|
|
369
380
|
self.custom_3d_styles[style_name] = {
|
|
370
381
|
'plugin': plugin_name, 'callback': callback
|
|
371
382
|
}
|
|
383
|
+
|
|
384
|
+
def register_document_reset_handler(self, plugin_name, callback):
|
|
385
|
+
"""Register callback to be invoked when a new document is created."""
|
|
386
|
+
self.document_reset_handlers.append({
|
|
387
|
+
'plugin': plugin_name,
|
|
388
|
+
'callback': callback
|
|
389
|
+
})
|
|
390
|
+
|
|
391
|
+
def invoke_document_reset_handlers(self):
|
|
392
|
+
"""Call all registered document reset handlers."""
|
|
393
|
+
for handler in self.document_reset_handlers:
|
|
394
|
+
try:
|
|
395
|
+
handler['callback']()
|
|
396
|
+
except Exception as e:
|
|
397
|
+
print(f"Error in document reset handler for {handler['plugin']}: {e}")
|
|
372
398
|
|
|
373
399
|
def get_plugin_info_safe(self, file_path):
|
|
374
400
|
"""Extracts plugin metadata using AST parsing (safe, no execution)."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MoleditPy
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.3
|
|
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=ehyCNblUR4uHs1xVpBAzY2-tQuuF05_6vGY7OYFTfbE,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
|
|
@@ -23,13 +23,13 @@ moleditpy/modules/main_window_app_state.py,sha256=8YDcGNCSpLTO1NGL9tEvNkXpUcS7JW
|
|
|
23
23
|
moleditpy/modules/main_window_compute.py,sha256=ipIkhH_DONXDnPzh7xeym9X-Yfx8EhsvXYOdyxsAj4c,53347
|
|
24
24
|
moleditpy/modules/main_window_dialog_manager.py,sha256=QR96LqHAPSOShXbc9cK-Ffq8a16JrXAoMKB0pHjESrQ,20072
|
|
25
25
|
moleditpy/modules/main_window_edit_3d.py,sha256=CUArB5wcsgq1C7LygAEC6URlbnn4RhRYDa5n-Y-etWI,19731
|
|
26
|
-
moleditpy/modules/main_window_edit_actions.py,sha256=
|
|
26
|
+
moleditpy/modules/main_window_edit_actions.py,sha256=MtCFmbKVAIMrm6hp0rUUNCQ37xYzE8MerVR7d1Coutk,65007
|
|
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=stZT2Swcd_yry3C_a7R2bC9-kew8yifRqy8Q3H3a3kk,93220
|
|
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=JfobFdAOLp5OnyJp3BNsWnpmZNJYypWQHNVNT0fP1N8,8171
|
|
42
|
+
moleditpy/modules/plugin_manager.py,sha256=ZFQz8VlCy1_IHX7DnMro7iRbouB_rxZQowfrKuZ76G8,21133
|
|
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.3.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
55
|
+
moleditpy-2.3.3.dist-info/METADATA,sha256=VbBIVoZs0NPTK88hUAwg8s9MVwt6aVqsIqs1NYcM0po,60629
|
|
56
|
+
moleditpy-2.3.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
57
|
+
moleditpy-2.3.3.dist-info/entry_points.txt,sha256=yH1h9JjALhok1foXT3-hYrC4ufoZt8b7oiBcsdnGNNM,54
|
|
58
|
+
moleditpy-2.3.3.dist-info/top_level.txt,sha256=ARICrS4ihlPXqywlKl6o-oJa3Qz3gZRWu_VZsQ3_c44,10
|
|
59
|
+
moleditpy-2.3.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|