MoleditPy 2.2.0a0__py3-none-any.whl → 2.2.0a1__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 +73 -103
- moleditpy/modules/plugin_manager.py +10 -0
- moleditpy/plugins/Analysis/ms_spectrum_neo.py +919 -0
- moleditpy/plugins/File/animated_xyz_giffer.py +583 -0
- moleditpy/plugins/File/cube_viewer.py +689 -0
- moleditpy/plugins/File/gaussian_fchk_freq_analyzer.py +1148 -0
- moleditpy/plugins/File/mapped_cube_viewer.py +552 -0
- moleditpy/plugins/File/orca_out_freq_analyzer.py +1226 -0
- moleditpy/plugins/File/paste_xyz.py +336 -0
- moleditpy/plugins/Input Generator/gaussian_input_generator_neo.py +930 -0
- moleditpy/plugins/Input Generator/orca_input_generator_neo.py +1028 -0
- moleditpy/plugins/Input Generator/orca_xyz2inp_gui.py +286 -0
- moleditpy/plugins/Optimization/all-trans_optimizer.py +65 -0
- moleditpy/plugins/Optimization/complex_molecule_untangler.py +268 -0
- moleditpy/plugins/Optimization/conf_search.py +224 -0
- moleditpy/plugins/Utility/atom_colorizer.py +547 -0
- moleditpy/plugins/Utility/console.py +163 -0
- moleditpy/plugins/Utility/pubchem_ressolver.py +244 -0
- moleditpy/plugins/Utility/vdw_radii_overlay.py +303 -0
- {moleditpy-2.2.0a0.dist-info → moleditpy-2.2.0a1.dist-info}/METADATA +1 -1
- {moleditpy-2.2.0a0.dist-info → moleditpy-2.2.0a1.dist-info}/RECORD +26 -9
- {moleditpy-2.2.0a0.dist-info → moleditpy-2.2.0a1.dist-info}/WHEEL +0 -0
- {moleditpy-2.2.0a0.dist-info → moleditpy-2.2.0a1.dist-info}/entry_points.txt +0 -0
- {moleditpy-2.2.0a0.dist-info → moleditpy-2.2.0a1.dist-info}/licenses/LICENSE +0 -0
- {moleditpy-2.2.0a0.dist-info → moleditpy-2.2.0a1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import io
|
|
3
|
+
import code
|
|
4
|
+
import traceback
|
|
5
|
+
from contextlib import redirect_stdout, redirect_stderr
|
|
6
|
+
from PyQt6.QtWidgets import (
|
|
7
|
+
QDialog, QVBoxLayout, QTextEdit, QLineEdit,
|
|
8
|
+
QPushButton, QLabel, QWidget
|
|
9
|
+
)
|
|
10
|
+
from PyQt6.QtGui import QFont, QColor
|
|
11
|
+
from PyQt6.QtCore import Qt
|
|
12
|
+
import rdkit.Chem as Chem
|
|
13
|
+
|
|
14
|
+
__version__="2025.12.25"
|
|
15
|
+
__author__="HiroYokoyama"
|
|
16
|
+
PLUGIN_NAME = "Python Console"
|
|
17
|
+
|
|
18
|
+
class HistoryLineEdit(QLineEdit):
|
|
19
|
+
def __init__(self, parent=None):
|
|
20
|
+
super().__init__(parent)
|
|
21
|
+
self.history = []
|
|
22
|
+
self.history_index = 0
|
|
23
|
+
|
|
24
|
+
def append_history(self, text):
|
|
25
|
+
if text and (not self.history or self.history[-1] != text):
|
|
26
|
+
self.history.append(text)
|
|
27
|
+
self.history_index = len(self.history)
|
|
28
|
+
|
|
29
|
+
def keyPressEvent(self, event):
|
|
30
|
+
if event.key() == Qt.Key.Key_Up:
|
|
31
|
+
if self.history_index > 0:
|
|
32
|
+
self.history_index -= 1
|
|
33
|
+
self.setText(self.history[self.history_index])
|
|
34
|
+
elif event.key() == Qt.Key.Key_Down:
|
|
35
|
+
if self.history_index < len(self.history) - 1:
|
|
36
|
+
self.history_index += 1
|
|
37
|
+
self.setText(self.history[self.history_index])
|
|
38
|
+
else:
|
|
39
|
+
self.history_index = len(self.history)
|
|
40
|
+
self.clear()
|
|
41
|
+
else:
|
|
42
|
+
super().keyPressEvent(event)
|
|
43
|
+
|
|
44
|
+
class PythonConsoleDialog(QDialog):
|
|
45
|
+
def __init__(self, main_window):
|
|
46
|
+
super().__init__(main_window)
|
|
47
|
+
self.main_window = main_window
|
|
48
|
+
self.setWindowTitle("MoleditPy Python Console")
|
|
49
|
+
self.resize(600, 400)
|
|
50
|
+
|
|
51
|
+
# UI Setup
|
|
52
|
+
layout = QVBoxLayout()
|
|
53
|
+
|
|
54
|
+
# Output Area (Log)
|
|
55
|
+
self.output_area = QTextEdit()
|
|
56
|
+
self.output_area.setReadOnly(True)
|
|
57
|
+
self.output_area.setStyleSheet("background-color: #1e1e1e; color: #dcdcdc;")
|
|
58
|
+
self.output_area.setFont(QFont("Consolas", 10))
|
|
59
|
+
layout.addWidget(self.output_area)
|
|
60
|
+
|
|
61
|
+
# Input Area with History
|
|
62
|
+
self.input_line = HistoryLineEdit()
|
|
63
|
+
self.input_line.setPlaceholderText("Enter Python code...")
|
|
64
|
+
self.input_line.setStyleSheet("background-color: #2d2d2d; color: #ffffff; border: 1px solid #3e3e3e;")
|
|
65
|
+
self.input_line.setFont(QFont("Consolas", 10))
|
|
66
|
+
self.input_line.returnPressed.connect(self.run_code)
|
|
67
|
+
layout.addWidget(self.input_line)
|
|
68
|
+
|
|
69
|
+
# Help Label
|
|
70
|
+
help_text = QLabel("Available vars: 'mw' (MainWindow), 'mol' (current_mol), 'Chem' (rdkit.Chem)")
|
|
71
|
+
help_text.setStyleSheet("color: gray; font-size: 10px;")
|
|
72
|
+
layout.addWidget(help_text)
|
|
73
|
+
|
|
74
|
+
self.setLayout(layout)
|
|
75
|
+
|
|
76
|
+
# Initialize execution environment (namespace)
|
|
77
|
+
self.local_scope = {
|
|
78
|
+
'mw': self.main_window,
|
|
79
|
+
'Chem': Chem,
|
|
80
|
+
'mol': self._get_best_mol(),
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
# Initialize Interpreter
|
|
84
|
+
self.interpreter = code.InteractiveInterpreter(self.local_scope)
|
|
85
|
+
|
|
86
|
+
self.append_output("MoleditPy Console Ready.")
|
|
87
|
+
self.append_output(">>> Type commands and press Enter.")
|
|
88
|
+
|
|
89
|
+
def _get_best_mol(self):
|
|
90
|
+
"""Helper to get the most relevant RDKit molecule object.
|
|
91
|
+
"""
|
|
92
|
+
mol = getattr(self.main_window, 'current_mol', None)
|
|
93
|
+
|
|
94
|
+
return mol
|
|
95
|
+
|
|
96
|
+
def append_output(self, text, color=None):
|
|
97
|
+
if color:
|
|
98
|
+
self.output_area.append(f"<span style='color: {color};'>{text}</span>")
|
|
99
|
+
else:
|
|
100
|
+
self.output_area.append(text)
|
|
101
|
+
|
|
102
|
+
def run_code(self):
|
|
103
|
+
command = self.input_line.text()
|
|
104
|
+
if not command:
|
|
105
|
+
return
|
|
106
|
+
|
|
107
|
+
# Handle History
|
|
108
|
+
self.input_line.append_history(command)
|
|
109
|
+
self.input_line.clear()
|
|
110
|
+
|
|
111
|
+
# Display Input
|
|
112
|
+
self.append_output(f">>> {command}", color="#4CAF50")
|
|
113
|
+
|
|
114
|
+
# Sync variables
|
|
115
|
+
self.local_scope['mol'] = self._get_best_mol()
|
|
116
|
+
|
|
117
|
+
if self.local_scope['mol'] is None:
|
|
118
|
+
# Optional: warn user if they try to use 'mol' and it's still None
|
|
119
|
+
# but only if 'mol' appears in command to avoid spam
|
|
120
|
+
if 'mol' in command:
|
|
121
|
+
print("Warning: 'mol' is None (no valid 2D or 3D structure found).")
|
|
122
|
+
|
|
123
|
+
# Capture Output
|
|
124
|
+
stdout_capture = io.StringIO()
|
|
125
|
+
stderr_capture = io.StringIO()
|
|
126
|
+
|
|
127
|
+
try:
|
|
128
|
+
with redirect_stdout(stdout_capture), redirect_stderr(stderr_capture):
|
|
129
|
+
# runsource handles compilation and syntax errors.
|
|
130
|
+
# It returns True if more input is needed (incomplete code), which we can handle or just report.
|
|
131
|
+
more = self.interpreter.runsource(command, "<console>", "single")
|
|
132
|
+
|
|
133
|
+
if more:
|
|
134
|
+
print("(Incomplete input - multiline not fully supported yet)")
|
|
135
|
+
except Exception:
|
|
136
|
+
# This catches errors OUTSIDE runsource's internal handling if any
|
|
137
|
+
traceback.print_exc(file=stderr_capture)
|
|
138
|
+
|
|
139
|
+
# Process Captured Output
|
|
140
|
+
out_str = stdout_capture.getvalue()
|
|
141
|
+
err_str = stderr_capture.getvalue()
|
|
142
|
+
|
|
143
|
+
if out_str:
|
|
144
|
+
self.output_area.append(out_str.strip())
|
|
145
|
+
if err_str:
|
|
146
|
+
self.append_output(err_str.strip(), color="#FF5252")
|
|
147
|
+
|
|
148
|
+
# Refresh UI if needed
|
|
149
|
+
# If the user modified 'mol', we might want to push it back?
|
|
150
|
+
# For now, read-only assumption for simpler integration,
|
|
151
|
+
# but if they modify 'mw.data' directly, we might need a refresh.
|
|
152
|
+
pass
|
|
153
|
+
|
|
154
|
+
# Plugin Entry Point
|
|
155
|
+
def run(mw):
|
|
156
|
+
if not hasattr(mw, 'python_console_dialog'):
|
|
157
|
+
mw.python_console_dialog = PythonConsoleDialog(mw)
|
|
158
|
+
|
|
159
|
+
mw.python_console_dialog.show()
|
|
160
|
+
mw.python_console_dialog.raise_()
|
|
161
|
+
mw.python_console_dialog.activateWindow()
|
|
162
|
+
|
|
163
|
+
# initialize removed as it only registered the menu action
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import requests # API通信に必要 (pip install requests)
|
|
3
|
+
from PyQt6.QtWidgets import (
|
|
4
|
+
QDialog, QVBoxLayout, QHBoxLayout, QTableWidget,
|
|
5
|
+
QTableWidgetItem, QPushButton, QMessageBox, QLabel, QHeaderView,
|
|
6
|
+
QAbstractItemView, QApplication, QLineEdit, QComboBox
|
|
7
|
+
)
|
|
8
|
+
from PyQt6.QtCore import Qt, QPointF
|
|
9
|
+
from rdkit import Chem
|
|
10
|
+
from rdkit.Chem import AllChem
|
|
11
|
+
|
|
12
|
+
__version__="2025.12.25"
|
|
13
|
+
__author__="HiroYokoyama"
|
|
14
|
+
PLUGIN_NAME = "PubChem Name Resolver"
|
|
15
|
+
|
|
16
|
+
class MoleculeResolverDialog(QDialog):
|
|
17
|
+
def __init__(self, main_window, parent=None):
|
|
18
|
+
super().__init__(parent)
|
|
19
|
+
self.main_window = main_window
|
|
20
|
+
self.setWindowTitle("PubChem Name Resolver")
|
|
21
|
+
self.resize(500, 600)
|
|
22
|
+
|
|
23
|
+
# 取得した候補データのリスト
|
|
24
|
+
# 各要素は辞書: {'name': str, 'smiles': str, 'formula': str}
|
|
25
|
+
self.candidates_data = []
|
|
26
|
+
|
|
27
|
+
# 生成されたRDKit分子オブジェクト(一時保存)
|
|
28
|
+
self.generated_mol = None
|
|
29
|
+
|
|
30
|
+
self.init_ui()
|
|
31
|
+
|
|
32
|
+
def init_ui(self):
|
|
33
|
+
layout = QVBoxLayout(self)
|
|
34
|
+
|
|
35
|
+
# --- 入力エリア ---
|
|
36
|
+
input_layout = QHBoxLayout()
|
|
37
|
+
|
|
38
|
+
self.combo_type = QComboBox()
|
|
39
|
+
self.combo_type.addItems(["Auto (Name/CAS)", "SMILES"])
|
|
40
|
+
input_layout.addWidget(self.combo_type)
|
|
41
|
+
|
|
42
|
+
self.line_input = QLineEdit()
|
|
43
|
+
self.line_input.setPlaceholderText("Enter Name or SMILES...")
|
|
44
|
+
self.line_input.returnPressed.connect(self.run_search) # Enterキーで検索
|
|
45
|
+
input_layout.addWidget(self.line_input)
|
|
46
|
+
|
|
47
|
+
self.btn_search = QPushButton("Search Online")
|
|
48
|
+
self.btn_search.clicked.connect(self.run_search)
|
|
49
|
+
input_layout.addWidget(self.btn_search)
|
|
50
|
+
|
|
51
|
+
layout.addLayout(input_layout)
|
|
52
|
+
|
|
53
|
+
# --- 説明ラベル ---
|
|
54
|
+
self.lbl_info = QLabel("Enter a chemical identifier and click Search.")
|
|
55
|
+
layout.addWidget(self.lbl_info)
|
|
56
|
+
|
|
57
|
+
# --- 結果表示用テーブル ---
|
|
58
|
+
self.table = QTableWidget()
|
|
59
|
+
self.table.setColumnCount(3)
|
|
60
|
+
self.table.setHorizontalHeaderLabels(["Name/Synonym", "Formula", "SMILES"])
|
|
61
|
+
# ヘッダー調整
|
|
62
|
+
header = self.table.horizontalHeader()
|
|
63
|
+
header.setSectionResizeMode(0, QHeaderView.ResizeMode.Stretch)
|
|
64
|
+
header.setSectionResizeMode(1, QHeaderView.ResizeMode.ResizeToContents)
|
|
65
|
+
header.setSectionResizeMode(2, QHeaderView.ResizeMode.Stretch)
|
|
66
|
+
|
|
67
|
+
self.table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
|
68
|
+
self.table.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
|
69
|
+
# 選択変更時にロードボタンを有効化するなどの処理を入れるならここ
|
|
70
|
+
layout.addWidget(self.table)
|
|
71
|
+
|
|
72
|
+
# --- ボタンエリア ---
|
|
73
|
+
btn_layout = QHBoxLayout()
|
|
74
|
+
|
|
75
|
+
self.btn_load = QPushButton("Load to 2D Editor")
|
|
76
|
+
self.btn_load.clicked.connect(self.load_molecule)
|
|
77
|
+
|
|
78
|
+
self.btn_close = QPushButton("Close")
|
|
79
|
+
self.btn_close.clicked.connect(self.close)
|
|
80
|
+
|
|
81
|
+
btn_layout.addWidget(self.btn_load)
|
|
82
|
+
btn_layout.addWidget(self.btn_close)
|
|
83
|
+
layout.addLayout(btn_layout)
|
|
84
|
+
|
|
85
|
+
def run_search(self):
|
|
86
|
+
query = self.line_input.text().strip()
|
|
87
|
+
if not query:
|
|
88
|
+
return
|
|
89
|
+
|
|
90
|
+
self.lbl_info.setText("Searching PubChem... please wait.")
|
|
91
|
+
self.btn_search.setEnabled(False)
|
|
92
|
+
self.table.setRowCount(0)
|
|
93
|
+
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
|
|
94
|
+
QApplication.processEvents()
|
|
95
|
+
|
|
96
|
+
results = []
|
|
97
|
+
error_msg = None
|
|
98
|
+
network_error = False
|
|
99
|
+
|
|
100
|
+
try:
|
|
101
|
+
search_type = self.combo_type.currentText()
|
|
102
|
+
|
|
103
|
+
if search_type == "SMILES":
|
|
104
|
+
# SMILESの場合は直接リストに追加(検証含む)
|
|
105
|
+
mol = Chem.MolFromSmiles(query)
|
|
106
|
+
if mol:
|
|
107
|
+
results.append({
|
|
108
|
+
'name': 'User Input SMILES',
|
|
109
|
+
'smiles': query,
|
|
110
|
+
'formula': Chem.rdMolDescriptors.CalcMolFormula(mol)
|
|
111
|
+
})
|
|
112
|
+
else:
|
|
113
|
+
raise ValueError("Invalid SMILES string.")
|
|
114
|
+
|
|
115
|
+
else: # Auto (PubChem API)
|
|
116
|
+
# PUG REST APIを使用して検索
|
|
117
|
+
# プロパティとしてSMILESと分子式を取得
|
|
118
|
+
# CanonicalSMILESも取得してフォールバックに使用
|
|
119
|
+
url = f"https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/name/{query}/property/IsomericSMILES,CanonicalSMILES,MolecularFormula,Title/JSON"
|
|
120
|
+
|
|
121
|
+
response = requests.get(url, timeout=10)
|
|
122
|
+
|
|
123
|
+
if response.status_code == 200:
|
|
124
|
+
data = response.json()
|
|
125
|
+
props = data.get('PropertyTable', {}).get('Properties', [])
|
|
126
|
+
for p in props:
|
|
127
|
+
# SMILESの取得(Isomericを優先、なければCanonical、それでもなければキー検索)
|
|
128
|
+
smiles = p.get('IsomericSMILES')
|
|
129
|
+
if not smiles:
|
|
130
|
+
smiles = p.get('CanonicalSMILES')
|
|
131
|
+
|
|
132
|
+
# まだ取得できていない場合、キー名に'SMILES'が含まれるものを探す
|
|
133
|
+
if not smiles:
|
|
134
|
+
for k in p.keys():
|
|
135
|
+
if 'SMILES' in k:
|
|
136
|
+
smiles = p[k]
|
|
137
|
+
if smiles:
|
|
138
|
+
break
|
|
139
|
+
|
|
140
|
+
if not smiles:
|
|
141
|
+
smiles = "" # 見つからない場合
|
|
142
|
+
|
|
143
|
+
results.append({
|
|
144
|
+
'name': p.get('Title', query),
|
|
145
|
+
'smiles': smiles,
|
|
146
|
+
'formula': p.get('MolecularFormula', '')
|
|
147
|
+
})
|
|
148
|
+
else:
|
|
149
|
+
# found nothing or error status
|
|
150
|
+
pass
|
|
151
|
+
|
|
152
|
+
except requests.exceptions.RequestException:
|
|
153
|
+
network_error = True
|
|
154
|
+
except Exception as e:
|
|
155
|
+
error_msg = str(e)
|
|
156
|
+
finally:
|
|
157
|
+
QApplication.restoreOverrideCursor()
|
|
158
|
+
self.btn_search.setEnabled(True)
|
|
159
|
+
|
|
160
|
+
# UI updates after cursor restore
|
|
161
|
+
if network_error:
|
|
162
|
+
QMessageBox.critical(self, PLUGIN_NAME, "Network error. Please check your internet connection.")
|
|
163
|
+
self.lbl_info.setText("Network error.")
|
|
164
|
+
elif error_msg:
|
|
165
|
+
QMessageBox.critical(self, PLUGIN_NAME, f"Error: {error_msg}")
|
|
166
|
+
self.lbl_info.setText("Error occurred.")
|
|
167
|
+
elif not results and 'response' in locals() and response.status_code != 200:
|
|
168
|
+
self.lbl_info.setText("Not found in PubChem search.")
|
|
169
|
+
else:
|
|
170
|
+
# データを保持
|
|
171
|
+
self.candidates_data = results
|
|
172
|
+
self.update_table()
|
|
173
|
+
|
|
174
|
+
if results:
|
|
175
|
+
self.lbl_info.setText(f"Found {len(results)} candidates. Select one and click Load to 2D Editor.")
|
|
176
|
+
else:
|
|
177
|
+
self.lbl_info.setText("No results found.")
|
|
178
|
+
|
|
179
|
+
def update_table(self):
|
|
180
|
+
self.table.setRowCount(0)
|
|
181
|
+
|
|
182
|
+
for i, data in enumerate(self.candidates_data):
|
|
183
|
+
row_idx = self.table.rowCount()
|
|
184
|
+
self.table.insertRow(row_idx)
|
|
185
|
+
|
|
186
|
+
self.table.setItem(row_idx, 0, QTableWidgetItem(str(data['name'])))
|
|
187
|
+
self.table.setItem(row_idx, 1, QTableWidgetItem(str(data['formula'])))
|
|
188
|
+
self.table.setItem(row_idx, 2, QTableWidgetItem(str(data['smiles'])))
|
|
189
|
+
|
|
190
|
+
def load_molecule(self):
|
|
191
|
+
"""選択された行のSMILESから2D構造を生成し、メインウィンドウのエディタに入れる"""
|
|
192
|
+
selected_items = self.table.selectedItems()
|
|
193
|
+
if not selected_items:
|
|
194
|
+
QMessageBox.warning(self, PLUGIN_NAME, "Please select a molecule from the list.")
|
|
195
|
+
return
|
|
196
|
+
|
|
197
|
+
row = selected_items[0].row()
|
|
198
|
+
smiles = self.candidates_data[row]['smiles']
|
|
199
|
+
name = self.candidates_data[row]['name']
|
|
200
|
+
|
|
201
|
+
if not smiles:
|
|
202
|
+
QMessageBox.warning(self, PLUGIN_NAME, "No SMILES data available for this entry.")
|
|
203
|
+
return
|
|
204
|
+
|
|
205
|
+
self.lbl_info.setText("Loading into 2D Editor...")
|
|
206
|
+
QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
|
|
207
|
+
QApplication.processEvents()
|
|
208
|
+
|
|
209
|
+
success = False
|
|
210
|
+
error_msg = None
|
|
211
|
+
|
|
212
|
+
try:
|
|
213
|
+
# メインウィンドウのSMILES読み込み機能を使用
|
|
214
|
+
if hasattr(self.main_window, "load_from_smiles"):
|
|
215
|
+
self.main_window.load_from_smiles(smiles)
|
|
216
|
+
success = True
|
|
217
|
+
else:
|
|
218
|
+
error_msg = "Main window does not support 'load_from_smiles'."
|
|
219
|
+
|
|
220
|
+
except Exception as e:
|
|
221
|
+
error_msg = str(e)
|
|
222
|
+
|
|
223
|
+
finally:
|
|
224
|
+
QApplication.restoreOverrideCursor()
|
|
225
|
+
|
|
226
|
+
if success:
|
|
227
|
+
self.lbl_info.setText(f"Loaded: {name}")
|
|
228
|
+
QMessageBox.information(self, PLUGIN_NAME, f"Successfully loaded: {name}")
|
|
229
|
+
self.accept() # ダイアログを閉じる
|
|
230
|
+
elif error_msg:
|
|
231
|
+
QMessageBox.critical(self, PLUGIN_NAME, f"Error: {error_msg}")
|
|
232
|
+
self.lbl_info.setText("Load failed.")
|
|
233
|
+
|
|
234
|
+
def run(mw):
|
|
235
|
+
if hasattr(mw, "_molecule_resolver_dialog") and mw._molecule_resolver_dialog.isVisible():
|
|
236
|
+
mw._molecule_resolver_dialog.raise_()
|
|
237
|
+
mw._molecule_resolver_dialog.activateWindow()
|
|
238
|
+
return
|
|
239
|
+
|
|
240
|
+
dialog = MoleculeResolverDialog(mw, parent=mw)
|
|
241
|
+
mw._molecule_resolver_dialog = dialog
|
|
242
|
+
dialog.show()
|
|
243
|
+
|
|
244
|
+
# initialize removed as it only registered the menu action
|