MoleditPy-linux 2.3.1__tar.gz → 2.3.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 (64) hide show
  1. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/PKG-INFO +1 -1
  2. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/pyproject.toml +1 -1
  3. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/MoleditPy_linux.egg-info/PKG-INFO +1 -1
  4. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/constants.py +1 -1
  5. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/main_window_main_init.py +38 -19
  6. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/main_window_ui_manager.py +2 -6
  7. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/plugin_interface.py +4 -12
  8. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/plugin_manager.py +14 -5
  9. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/LICENSE +0 -0
  10. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/README.md +0 -0
  11. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/setup.cfg +0 -0
  12. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/MoleditPy_linux.egg-info/SOURCES.txt +0 -0
  13. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/MoleditPy_linux.egg-info/dependency_links.txt +0 -0
  14. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/MoleditPy_linux.egg-info/entry_points.txt +0 -0
  15. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/MoleditPy_linux.egg-info/requires.txt +0 -0
  16. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/MoleditPy_linux.egg-info/top_level.txt +0 -0
  17. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/__init__.py +0 -0
  18. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/__main__.py +0 -0
  19. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/main.py +0 -0
  20. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/__init__.py +0 -0
  21. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/about_dialog.py +0 -0
  22. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/align_plane_dialog.py +0 -0
  23. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/alignment_dialog.py +0 -0
  24. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/analysis_window.py +0 -0
  25. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/angle_dialog.py +0 -0
  26. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/assets/file_icon.ico +0 -0
  27. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/assets/icon.icns +0 -0
  28. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/assets/icon.ico +0 -0
  29. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/assets/icon.png +0 -0
  30. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/atom_item.py +0 -0
  31. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/bond_item.py +0 -0
  32. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/bond_length_dialog.py +0 -0
  33. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/calculation_worker.py +0 -0
  34. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/color_settings_dialog.py +0 -0
  35. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/constrained_optimization_dialog.py +0 -0
  36. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/custom_interactor_style.py +0 -0
  37. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/custom_qt_interactor.py +0 -0
  38. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/dialog3_d_picking_mixin.py +0 -0
  39. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/dihedral_dialog.py +0 -0
  40. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/main_window.py +0 -0
  41. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/main_window_app_state.py +0 -0
  42. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/main_window_compute.py +0 -0
  43. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/main_window_dialog_manager.py +0 -0
  44. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/main_window_edit_3d.py +0 -0
  45. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/main_window_edit_actions.py +0 -0
  46. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/main_window_export.py +0 -0
  47. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/main_window_molecular_parsers.py +0 -0
  48. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/main_window_project_io.py +0 -0
  49. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/main_window_string_importers.py +0 -0
  50. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/main_window_view_3d.py +0 -0
  51. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/main_window_view_loaders.py +0 -0
  52. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/mirror_dialog.py +0 -0
  53. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/molecular_data.py +0 -0
  54. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/molecule_scene.py +0 -0
  55. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/move_group_dialog.py +0 -0
  56. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/periodic_table_dialog.py +0 -0
  57. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/planarize_dialog.py +0 -0
  58. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/plugin_manager_window.py +0 -0
  59. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/settings_dialog.py +0 -0
  60. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/template_preview_item.py +0 -0
  61. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/template_preview_view.py +0 -0
  62. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/translation_dialog.py +0 -0
  63. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/user_template_dialog.py +0 -0
  64. {moleditpy_linux-2.3.1 → moleditpy_linux-2.3.2}/src/moleditpy_linux/modules/zoomable_view.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MoleditPy-linux
3
- Version: 2.3.1
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
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "MoleditPy-linux"
7
7
 
8
- version = "2.3.1"
8
+ version = "2.3.2"
9
9
 
10
10
  license = {file = "LICENSE"}
11
11
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MoleditPy-linux
3
- Version: 2.3.1
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
@@ -16,7 +16,7 @@ from PyQt6.QtGui import QFont, QColor
16
16
  from rdkit import Chem
17
17
 
18
18
  #Version
19
- VERSION = '2.3.1'
19
+ VERSION = '2.3.2'
20
20
 
21
21
  ATOM_RADIUS = 18
22
22
  BOND_OFFSET = 3.5
@@ -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
- opener = self.plugin_manager.file_openers[ext_with_dot]
1456
- try:
1457
- opener['callback'](file_path)
1458
- self.current_file_path = file_path
1459
- self.update_window_title()
1460
- return
1461
- except Exception as e:
1462
- print(f"Plugin opener failed: {e}")
1463
- QMessageBox.warning(self, "Plugin Error", f"Error opening file with plugin '{opener.get('plugin', 'Unknown')}':\n{e}")
1464
- # Fallback to standard logic if plugin fails? Or stop?
1465
- # Generally if a plugin claims it, we stop. But here we let it fall through if it errors?
1466
- # Let's simple check next.
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, info in self.plugin_manager.file_openers.items():
1982
- p_name = info.get('plugin', 'Plugin')
1983
- if p_name not in plugin_map:
1984
- plugin_map[p_name] = {}
1985
- plugin_map[p_name][ext] = info['callback']
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-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
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 = {}
@@ -345,14 +345,23 @@ class PluginManager:
345
345
  'plugin': plugin_name, 'callback': callback, 'label': method_name
346
346
  }
347
347
 
348
- def register_file_opener(self, plugin_name, extension, callback):
348
+ def register_file_opener(self, plugin_name, extension, callback, priority=0):
349
349
  # Normalize extension to lowercase
350
350
  ext = extension.lower()
351
351
  if not ext.startswith('.'):
352
352
  ext = '.' + ext
353
- self.file_openers[ext] = {
354
- 'plugin': plugin_name, 'callback': callback
355
- }
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)
356
365
 
357
366
  # Analysis Tools registration
358
367
  def register_analysis_tool(self, plugin_name, label, callback):
File without changes