MoleditPy 2.2.0__tar.gz → 2.2.0a0__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-2.2.0 → moleditpy-2.2.0a0}/PKG-INFO +1 -1
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/pyproject.toml +1 -1
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/MoleditPy.egg-info/PKG-INFO +1 -1
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/constants.py +1 -1
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/main_window_main_init.py +105 -93
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/main_window_ui_manager.py +2 -21
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/plugin_interface.py +10 -1
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/plugin_manager.py +2 -9
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/LICENSE +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/README.md +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/setup.cfg +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/MoleditPy.egg-info/SOURCES.txt +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/MoleditPy.egg-info/dependency_links.txt +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/MoleditPy.egg-info/entry_points.txt +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/MoleditPy.egg-info/requires.txt +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/MoleditPy.egg-info/top_level.txt +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/__init__.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/__main__.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/main.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/__init__.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/about_dialog.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/align_plane_dialog.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/alignment_dialog.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/analysis_window.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/angle_dialog.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/assets/icon.icns +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/assets/icon.ico +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/assets/icon.png +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/atom_item.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/bond_item.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/bond_length_dialog.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/calculation_worker.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/color_settings_dialog.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/constrained_optimization_dialog.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/custom_interactor_style.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/custom_qt_interactor.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/dialog3_d_picking_mixin.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/dihedral_dialog.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/main_window.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/main_window_app_state.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/main_window_compute.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/main_window_dialog_manager.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/main_window_edit_3d.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/main_window_edit_actions.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/main_window_export.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/main_window_molecular_parsers.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/main_window_project_io.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/main_window_string_importers.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/main_window_view_3d.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/main_window_view_loaders.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/mirror_dialog.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/molecular_data.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/molecule_scene.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/move_group_dialog.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/periodic_table_dialog.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/planarize_dialog.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/plugin_manager_window.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/settings_dialog.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/template_preview_item.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/template_preview_view.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/translation_dialog.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/user_template_dialog.py +0 -0
- {moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/zoomable_view.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MoleditPy
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.0a0
|
|
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
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.0a0
|
|
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
|
|
@@ -32,7 +32,7 @@ except Exception:
|
|
|
32
32
|
# PyQt6 Modules
|
|
33
33
|
from PyQt6.QtWidgets import (
|
|
34
34
|
QApplication, QWidget, QVBoxLayout, QHBoxLayout,
|
|
35
|
-
QPushButton, QSplitter, QToolBar, QSizePolicy, QLabel, QToolButton, QMenu, QMessageBox
|
|
35
|
+
QPushButton, QSplitter, QToolBar, QSizePolicy, QLabel, QToolButton, QMenu, QMessageBox
|
|
36
36
|
)
|
|
37
37
|
|
|
38
38
|
from PyQt6.QtGui import (
|
|
@@ -1755,32 +1755,10 @@ class MainWindowMainInit(object):
|
|
|
1755
1755
|
"""Discovers plugins and updates the plugin menu actions."""
|
|
1756
1756
|
if not self.plugin_manager:
|
|
1757
1757
|
return
|
|
1758
|
-
|
|
1759
|
-
PLUGIN_ACTION_TAG = "plugin_managed"
|
|
1760
|
-
|
|
1761
|
-
# Helper to clear tagged actions from a menu
|
|
1762
|
-
def clear_plugin_actions(menu):
|
|
1763
|
-
if not menu: return
|
|
1764
|
-
for act in list(menu.actions()):
|
|
1765
|
-
if act.data() == PLUGIN_ACTION_TAG:
|
|
1766
|
-
menu.removeAction(act)
|
|
1767
|
-
# Recurse into submenus to clean deep actions
|
|
1768
|
-
elif act.menu():
|
|
1769
|
-
clear_plugin_actions(act.menu())
|
|
1770
1758
|
|
|
1771
|
-
# Clear existing plugin actions
|
|
1759
|
+
# Clear existing plugin actions
|
|
1772
1760
|
plugin_menu.clear()
|
|
1773
1761
|
|
|
1774
|
-
# Clear tagged actions from ALL top-level menus in the Menu Bar
|
|
1775
|
-
# This ensures we catch actions added to standard menus (File, Edit) OR custom menus
|
|
1776
|
-
for top_action in self.menuBar().actions():
|
|
1777
|
-
if top_action.menu():
|
|
1778
|
-
clear_plugin_actions(top_action.menu())
|
|
1779
|
-
|
|
1780
|
-
# Clear Export menu (if button exists)
|
|
1781
|
-
if hasattr(self, 'export_button') and self.export_button.menu():
|
|
1782
|
-
clear_plugin_actions(self.export_button.menu())
|
|
1783
|
-
|
|
1784
1762
|
# Only keep the Manager action
|
|
1785
1763
|
manage_plugins_action = QAction("Plugin Manager...", self)
|
|
1786
1764
|
def show_plugin_manager():
|
|
@@ -1836,9 +1814,9 @@ class MainWindowMainInit(object):
|
|
|
1836
1814
|
action_text = text if text else parts[-1]
|
|
1837
1815
|
action = QAction(action_text, self)
|
|
1838
1816
|
action.triggered.connect(callback)
|
|
1839
|
-
action.setData(PLUGIN_ACTION_TAG) # TAG THE ACTION
|
|
1840
1817
|
current_menu.addAction(action)
|
|
1841
1818
|
|
|
1819
|
+
# 2. Add Toolbar Buttons (New System)
|
|
1842
1820
|
# 2. Add Toolbar Buttons (New System)
|
|
1843
1821
|
# Use dedicated plugin toolbar
|
|
1844
1822
|
if hasattr(self, 'plugin_toolbar'):
|
|
@@ -1862,12 +1840,14 @@ class MainWindowMainInit(object):
|
|
|
1862
1840
|
self.plugin_toolbar.hide()
|
|
1863
1841
|
|
|
1864
1842
|
# 3. Legacy Menu Building (Folder based)
|
|
1843
|
+
|
|
1865
1844
|
if not plugins:
|
|
1866
1845
|
no_plugin_action = QAction("(No plugins found)", self)
|
|
1867
1846
|
no_plugin_action.setEnabled(False)
|
|
1868
1847
|
plugin_menu.addAction(no_plugin_action)
|
|
1869
1848
|
else:
|
|
1870
1849
|
# Sort plugins: directories first (to create menus), then alphabetical by name
|
|
1850
|
+
# Actually simple sort by rel_folder, name is fine
|
|
1871
1851
|
plugins.sort(key=lambda x: (x.get('rel_folder', ''), x['name']))
|
|
1872
1852
|
|
|
1873
1853
|
# Dictionary to keep track of created submenus: path -> QMenu
|
|
@@ -1875,6 +1855,7 @@ class MainWindowMainInit(object):
|
|
|
1875
1855
|
|
|
1876
1856
|
for p in plugins:
|
|
1877
1857
|
# Only add legacy plugins (with 'run' function) to the generic Plugins menu.
|
|
1858
|
+
# New plugins (with 'initialize') should register their own menu actions if needed.
|
|
1878
1859
|
if hasattr(p['module'], 'run'):
|
|
1879
1860
|
rel_folder = p.get('rel_folder', '')
|
|
1880
1861
|
# Get or create the parent menu for this plugin
|
|
@@ -1901,83 +1882,114 @@ class MainWindowMainInit(object):
|
|
|
1901
1882
|
parent_menu.addAction(action)
|
|
1902
1883
|
|
|
1903
1884
|
# 4. Integrate Export Actions into Export Button and Menu
|
|
1904
|
-
# 4. Integrate Export Actions into Export Button AND Main File->Export Menu
|
|
1905
1885
|
if self.plugin_manager.export_actions:
|
|
1906
|
-
#
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
main_export_menu = sub_action.menu()
|
|
1913
|
-
break
|
|
1914
|
-
if main_export_menu: break
|
|
1915
|
-
|
|
1916
|
-
# List of menus to populate
|
|
1917
|
-
target_menus = []
|
|
1886
|
+
# Add separator if we have custom exports (and haven't added it yet for this session/update)
|
|
1887
|
+
# Since update_plugin_menu clears the dynamic plugin actions but NOT the export menu (which is on a button),
|
|
1888
|
+
# we need to be careful not to duplicate.
|
|
1889
|
+
# Ideally, we should clear custom actions from the export menu first.
|
|
1890
|
+
# For simplicity, we'll just check existence.
|
|
1891
|
+
|
|
1918
1892
|
if hasattr(self, 'export_button') and self.export_button.menu():
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
a.triggered.connect(callback)
|
|
1934
|
-
a.setData(PLUGIN_ACTION_TAG)
|
|
1935
|
-
menu.addAction(a)
|
|
1893
|
+
# Naive approach: check if separator/actions exist.
|
|
1894
|
+
# Better approach: Add them to a specific section or manage them explicitly.
|
|
1895
|
+
# Here we just append if not present.
|
|
1896
|
+
|
|
1897
|
+
# Check if we need a separator (if we have built-in actions)
|
|
1898
|
+
if self.export_button.menu().actions():
|
|
1899
|
+
has_sep = False
|
|
1900
|
+
for a in self.export_button.menu().actions():
|
|
1901
|
+
if a.isSeparator():
|
|
1902
|
+
has_sep = True
|
|
1903
|
+
# Get or create the parent menu for this plugin
|
|
1904
|
+
# For folder based hierarchy only?
|
|
1905
|
+
# ... (Refer to existing code for menu building, skipped here for brevity)
|
|
1906
|
+
pass
|
|
1936
1907
|
|
|
1937
1908
|
# 5. Integrate File Openers into Import Menu
|
|
1938
1909
|
if hasattr(self, 'import_menu') and self.plugin_manager.file_openers:
|
|
1939
|
-
# Add separator
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1910
|
+
# Add a separator if plugins are present
|
|
1911
|
+
has_plugins = len(self.plugin_manager.file_openers) > 0
|
|
1912
|
+
if has_plugins:
|
|
1913
|
+
self.import_menu.addSeparator()
|
|
1914
|
+
|
|
1943
1915
|
for ext, info in self.plugin_manager.file_openers.items():
|
|
1916
|
+
# ext e.g. .xyz
|
|
1917
|
+
# info = {'plugin': name, 'callback': cb}
|
|
1944
1918
|
label = f"Import {ext} ({info.get('plugin', 'Plugin')})..."
|
|
1945
1919
|
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1920
|
+
# duplicate check
|
|
1921
|
+
exists = False
|
|
1922
|
+
for act in self.import_menu.actions():
|
|
1923
|
+
if act.text() == label:
|
|
1924
|
+
exists = True
|
|
1925
|
+
break
|
|
1926
|
+
|
|
1927
|
+
if not exists:
|
|
1928
|
+
def make_cb(callback):
|
|
1929
|
+
def _cb():
|
|
1930
|
+
# Standard file dialog to pick file, then callback
|
|
1931
|
+
fpath, _ = QFileDialog.getOpenFileName(
|
|
1932
|
+
self, f"Import {ext}", "",
|
|
1933
|
+
f"{info.get('plugin', 'Plugin')} File (*{ext});;All Files (*)"
|
|
1934
|
+
)
|
|
1935
|
+
if fpath:
|
|
1936
|
+
callback(fpath)
|
|
1937
|
+
self.current_file_path = fpath # Update current file path?
|
|
1938
|
+
self.update_window_title()
|
|
1939
|
+
return _cb
|
|
1940
|
+
|
|
1941
|
+
a = QAction(label, self)
|
|
1942
|
+
a.triggered.connect(make_cb(info['callback']))
|
|
1943
|
+
self.import_menu.addAction(a)
|
|
1962
1944
|
|
|
1963
1945
|
# 6. Integrate Analysis Tools into Analysis Menu
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
break
|
|
1970
|
-
|
|
1971
|
-
if analysis_menu and self.plugin_manager.analysis_tools:
|
|
1972
|
-
# Add separator
|
|
1973
|
-
sep = analysis_menu.addSeparator()
|
|
1974
|
-
sep.setData(PLUGIN_ACTION_TAG)
|
|
1946
|
+
if hasattr(self, 'analysis_action') and self.plugin_manager.analysis_tools:
|
|
1947
|
+
# Determine parent menu (Analysis)
|
|
1948
|
+
# self.analysis_action is just an action, we need the menu it belongs to?
|
|
1949
|
+
# Or did we stash the analysis_menu?
|
|
1950
|
+
# Looking at init, analysis_menu wasn't stored as self.analysis_menu, but we can find it via menuBar.
|
|
1975
1951
|
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1952
|
+
# Let's find "Analysis" menu
|
|
1953
|
+
analysis_menu = None
|
|
1954
|
+
for action in self.menuBar().actions():
|
|
1955
|
+
if action.text().replace('&', '') == 'Analysis':
|
|
1956
|
+
analysis_menu = action.menu()
|
|
1957
|
+
break
|
|
1958
|
+
|
|
1959
|
+
if analysis_menu:
|
|
1960
|
+
# Add separator if we have plugins
|
|
1961
|
+
if self.plugin_manager.analysis_tools:
|
|
1962
|
+
analysis_menu.addSeparator()
|
|
1963
|
+
|
|
1964
|
+
for tool in self.plugin_manager.analysis_tools:
|
|
1965
|
+
label = f"{tool['label']} ({tool.get('plugin', 'Plugin')})"
|
|
1966
|
+
# duplicate check
|
|
1967
|
+
exists = False
|
|
1968
|
+
for act in analysis_menu.actions():
|
|
1969
|
+
if act.text() == label:
|
|
1970
|
+
exists = True
|
|
1971
|
+
break
|
|
1972
|
+
if not exists:
|
|
1973
|
+
a = QAction(label, self)
|
|
1974
|
+
a.triggered.connect(tool['callback'])
|
|
1975
|
+
analysis_menu.addAction(a)
|
|
1976
|
+
|
|
1977
|
+
# 7. Integrate Export Actions (Continued)
|
|
1978
|
+
if self.plugin_manager.export_actions:
|
|
1979
|
+
for exp in self.plugin_manager.export_actions:
|
|
1980
|
+
label = exp['label']
|
|
1981
|
+
callback = exp['callback']
|
|
1982
|
+
|
|
1983
|
+
exists = False
|
|
1984
|
+
for act in self.export_button.menu().actions():
|
|
1985
|
+
if act.text() == label:
|
|
1986
|
+
exists = True
|
|
1987
|
+
break
|
|
1988
|
+
|
|
1989
|
+
if not exists:
|
|
1990
|
+
a = QAction(label, self)
|
|
1991
|
+
a.triggered.connect(callback)
|
|
1992
|
+
self.export_button.menu().addAction(a)
|
|
1993
|
+
|
|
1994
|
+
# 5. Integrate File Openers (Implicitly handled during file load) uses PluginManager directly
|
|
1983
1995
|
|
|
@@ -298,7 +298,7 @@ class MainWindowUiManager(object):
|
|
|
298
298
|
|
|
299
299
|
|
|
300
300
|
def dragEnterEvent(self, event):
|
|
301
|
-
"""
|
|
301
|
+
"""ウィンドウ全体で .pmeraw、.pmeprj、.mol、.sdf、.xyz ファイルのドラッグを受け入れる"""
|
|
302
302
|
# Accept if any dragged local file has a supported extension
|
|
303
303
|
if event.mimeData().hasUrls():
|
|
304
304
|
urls = event.mimeData().urls()
|
|
@@ -306,28 +306,9 @@ class MainWindowUiManager(object):
|
|
|
306
306
|
try:
|
|
307
307
|
if url.isLocalFile():
|
|
308
308
|
file_path = url.toLocalFile()
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
# Built-in extensions
|
|
312
|
-
if file_lower.endswith(('.pmeraw', '.pmeprj', '.mol', '.sdf', '.xyz')):
|
|
309
|
+
if file_path.lower().endswith(('.pmeraw', '.pmeprj', '.mol', '.sdf', '.xyz')):
|
|
313
310
|
event.acceptProposedAction()
|
|
314
311
|
return
|
|
315
|
-
|
|
316
|
-
# Plugin-registered file openers
|
|
317
|
-
if self.plugin_manager and hasattr(self.plugin_manager, 'file_openers'):
|
|
318
|
-
for ext in self.plugin_manager.file_openers.keys():
|
|
319
|
-
if file_lower.endswith(ext):
|
|
320
|
-
event.acceptProposedAction()
|
|
321
|
-
return
|
|
322
|
-
|
|
323
|
-
# Plugin drop handlers (accept more liberally for custom logic)
|
|
324
|
-
# A plugin drop handler might handle it, so accept
|
|
325
|
-
if self.plugin_manager and hasattr(self.plugin_manager, 'drop_handlers'):
|
|
326
|
-
if len(self.plugin_manager.drop_handlers) > 0:
|
|
327
|
-
# Accept any file if drop handlers are registered
|
|
328
|
-
# They will check the file type in dropEvent
|
|
329
|
-
event.acceptProposedAction()
|
|
330
|
-
return
|
|
331
312
|
except Exception:
|
|
332
313
|
continue
|
|
333
314
|
event.ignore()
|
|
@@ -159,7 +159,16 @@ class PluginContext:
|
|
|
159
159
|
self._manager.register_3d_style(self._plugin_name, style_name, callback)
|
|
160
160
|
|
|
161
161
|
|
|
162
|
-
|
|
162
|
+
def add_panel_button(self, text: str, callback: Callable, panel: str = "right"):
|
|
163
|
+
"""
|
|
164
|
+
Add a button to the bottom control panel.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
text: Label on the button.
|
|
168
|
+
callback: Function to call on click.
|
|
169
|
+
panel: "left" (2D Editor) or "right" (3D Viewer). Default "right".
|
|
170
|
+
"""
|
|
171
|
+
self._manager.register_panel_button(self._plugin_name, text, callback, panel)
|
|
163
172
|
|
|
164
173
|
|
|
165
174
|
|
|
@@ -40,6 +40,7 @@ class PluginManager:
|
|
|
40
40
|
# Registries for actions
|
|
41
41
|
self.menu_actions = [] # List of (plugin_name, path, callback, text, icon, shortcut)
|
|
42
42
|
self.toolbar_actions = []
|
|
43
|
+
self.context_menu_3d_actions = []
|
|
43
44
|
self.drop_handlers = [] # List of (priority, plugin_name, callback)
|
|
44
45
|
|
|
45
46
|
# Extended Registries (Added to prevent lazy initialization "monkey patching")
|
|
@@ -48,6 +49,7 @@ class PluginManager:
|
|
|
48
49
|
self.file_openers = {}
|
|
49
50
|
self.analysis_tools = []
|
|
50
51
|
self.save_handlers = {}
|
|
52
|
+
self.save_handlers = {}
|
|
51
53
|
self.load_handlers = {}
|
|
52
54
|
self.custom_3d_styles = {} # style_name -> {'plugin': name, 'callback': func}
|
|
53
55
|
|
|
@@ -98,15 +100,6 @@ class PluginManager:
|
|
|
98
100
|
self.toolbar_actions = []
|
|
99
101
|
self.drop_handlers = []
|
|
100
102
|
|
|
101
|
-
# Clear extended registries
|
|
102
|
-
self.export_actions = []
|
|
103
|
-
self.optimization_methods = {}
|
|
104
|
-
self.file_openers = {}
|
|
105
|
-
self.analysis_tools = []
|
|
106
|
-
self.save_handlers = {}
|
|
107
|
-
self.load_handlers = {}
|
|
108
|
-
self.custom_3d_styles = {}
|
|
109
|
-
|
|
110
103
|
if not os.path.exists(self.plugin_dir):
|
|
111
104
|
return []
|
|
112
105
|
|
|
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
|
|
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
|
|
File without changes
|
{moleditpy-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/constrained_optimization_dialog.py
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-2.2.0 → moleditpy-2.2.0a0}/src/moleditpy/modules/main_window_molecular_parsers.py
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|