finalcif 158__tar.gz → 159__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.
- {finalcif-158 → finalcif-159}/PKG-INFO +3 -3
- {finalcif-158 → finalcif-159}/README.md +2 -2
- finalcif-159/finalcif/__init__.py +2 -0
- {finalcif-158 → finalcif-159}/finalcif/appwindow.py +152 -136
- {finalcif-158 → finalcif-159}/finalcif/cif/checkcif/checkcif.py +25 -22
- {finalcif-158 → finalcif-159}/finalcif/cif/cif_file_io.py +16 -0
- finalcif-159/finalcif/cif/vrf_entry.py +92 -0
- {finalcif-158 → finalcif-159}/finalcif/equip_property/author_loop_templates.py +4 -4
- {finalcif-158 → finalcif-159}/finalcif/gui/cif_table_view.py +16 -1
- {finalcif-158 → finalcif-159}/finalcif/gui/finalcif_gui_ui.py +21 -78
- {finalcif-158 → finalcif-159}/finalcif/gui/finalcif_gui_ui.ui +19 -136
- {finalcif-158 → finalcif-159}/finalcif/gui/import_selector.py +3 -2
- {finalcif-158 → finalcif-159}/finalcif/gui/loop_creator.py +3 -0
- finalcif-159/finalcif/gui/loops.py +555 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/vrf_classes.py +72 -75
- {finalcif-158 → finalcif-159}/finalcif/report/templated_report.py +3 -1
- finalcif-159/finalcif/template/report_default.docx +0 -0
- finalcif-159/screenshots/loops_column_buttons.png +0 -0
- finalcif-158/finalcif/__init__.py +0 -2
- finalcif-158/finalcif/gui/loops.py +0 -332
- finalcif-158/finalcif/template/report_default.docx +0 -0
- {finalcif-158 → finalcif-159}/.gitattributes +0 -0
- {finalcif-158 → finalcif-159}/.gitignore +0 -0
- {finalcif-158 → finalcif-159}/.python-version +0 -0
- {finalcif-158 → finalcif-159}/.ruff.toml +0 -0
- {finalcif-158 → finalcif-159}/.run/Make Documentation MAC.run.xml +0 -0
- {finalcif-158 → finalcif-159}/.run/compile_ui_files.run.xml +0 -0
- {finalcif-158 → finalcif-159}/.run/make documentation Windows.run.xml +0 -0
- {finalcif-158 → finalcif-159}/AGENTS.md +0 -0
- {finalcif-158 → finalcif-159}/CODE_OF_CONDUCT.md +0 -0
- {finalcif-158 → finalcif-159}/CONTRIBUTING.md +0 -0
- {finalcif-158 → finalcif-159}/Finalcif_installer_win.spec +0 -0
- {finalcif-158 → finalcif-159}/Finalcif_linux_onefile.spec +0 -0
- {finalcif-158 → finalcif-159}/Finalcif_mac.spec +0 -0
- {finalcif-158 → finalcif-159}/LICENSE +0 -0
- {finalcif-158 → finalcif-159}/finalcif/app_path.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/__init__.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/all_cif_dicts.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/atoms.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/checkcif/__init__.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/cif_dict_foo.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/cif_order.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/cod/__init__.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/cod/deposit.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/cod/deposit_check.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/cod/deposition_list.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/cod/doi.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/cod/upload.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/cod/website_parser.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/core_dict.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/hkl.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/modulation_dict.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/powder_dict.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/reference.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/restraints_dict.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/text.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/cif/twin_dict.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/ciforder/__init__.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/ciforder/order.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/ciforder/order_ui.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/ciforder/order_ui.ui +0 -0
- {finalcif-158 → finalcif-159}/finalcif/datafiles/__init__.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/datafiles/bruker_data.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/datafiles/bruker_frame.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/datafiles/ccdc_mail.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/datafiles/data.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/datafiles/p4p_reader.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/datafiles/sadabs.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/datafiles/saint.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/datafiles/shelx_lst.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/datafiles/utils.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/displaymol/__init__.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/displaymol/vtk_molecule.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/equip_property/__init__.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/equip_property/equipment.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/equip_property/properties.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/equip_property/tools.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/finalcif_start.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/__init__.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/block_combobox.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/cif_table_model.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/combobox.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/custom_classes.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/dialogs.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/edit_button.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/equipmenttable.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/file_editor.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/import_selector_ui.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/import_selector_ui.ui +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/loop_creator_ui.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/loop_creator_ui.ui +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/mainstackwidget.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/mixins.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/new_key_dialog.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/new_key_dialog_ui.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/new_key_dialog_ui.ui +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/plaintextedit.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/playground.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/propertytable.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/spell_check_edit.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/syntax_highlighter.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/text_templates_ui.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/text_templates_ui.ui +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/text_value_editor.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/validators.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/gui/vzs_viewer.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/icon/__init__.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/icon/finalcif.png +0 -0
- {finalcif-158 → finalcif-159}/finalcif/icon/finalcif2.ico +0 -0
- {finalcif-158 → finalcif-159}/finalcif/icon/finalcif2.png +0 -0
- {finalcif-158 → finalcif-159}/finalcif/icon/multitable.ico +0 -0
- {finalcif-158 → finalcif-159}/finalcif/icon/multitable.png +0 -0
- {finalcif-158 → finalcif-159}/finalcif/icon/multitable.xcf +0 -0
- {finalcif-158 → finalcif-159}/finalcif/report/__init__.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/report/archive_report.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/report/gui/__init__.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/report/gui/mainwindow.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/report/gui/mainwindow.ui +0 -0
- {finalcif-158 → finalcif-159}/finalcif/report/mtools.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/report/references.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/report/report_text.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/report/symm.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/report/tables.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/template/__init__.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/template/bootstrap/bootstrap.min.css +0 -0
- {finalcif-158 → finalcif-159}/finalcif/template/machines/D8_VENTURE.cif +0 -0
- {finalcif-158 → finalcif-159}/finalcif/template/mathml2omml.xsl +0 -0
- {finalcif-158 → finalcif-159}/finalcif/template/report.tmpl +0 -0
- {finalcif-158 → finalcif-159}/finalcif/template/template1.docx +0 -0
- {finalcif-158 → finalcif-159}/finalcif/template/template_for_multitable.docx +0 -0
- {finalcif-158 → finalcif-159}/finalcif/template/template_text.docx +0 -0
- {finalcif-158 → finalcif-159}/finalcif/template/template_without_text.docx +0 -0
- {finalcif-158 → finalcif-159}/finalcif/template/templates.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/template/xsl/convert.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/template/xsl/xmltohtml.xsl +0 -0
- {finalcif-158 → finalcif-159}/finalcif/tools/__init__.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/tools/chemparse.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/tools/download.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/tools/dsrmath.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/tools/misc.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/tools/options.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/tools/platon.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/tools/pupdate.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/tools/settings.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/tools/shred.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/tools/space_groups.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/tools/spgr_format.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/tools/statusbar.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif/tools/sumformula.py +0 -0
- {finalcif-158 → finalcif-159}/finalcif.exe +0 -0
- {finalcif-158 → finalcif-159}/platon/README.txt +0 -0
- {finalcif-158 → finalcif-159}/platon/compile_platon.bat +0 -0
- {finalcif-158 → finalcif-159}/platon/platon_special.exe +0 -0
- {finalcif-158 → finalcif-159}/platon/platon_special.f +0 -0
- {finalcif-158 → finalcif-159}/pylock.toml +0 -0
- {finalcif-158 → finalcif-159}/pyproject.toml +0 -0
- {finalcif-158 → finalcif-159}/run_finalcif +0 -0
- {finalcif-158 → finalcif-159}/run_finalcif.bat +0 -0
- {finalcif-158 → finalcif-159}/screenshots/finalcif_checkcif.png +0 -0
- {finalcif-158 → finalcif-159}/screenshots/finalcif_details.png +0 -0
- {finalcif-158 → finalcif-159}/screenshots/finalcif_loops.png +0 -0
- {finalcif-158 → finalcif-159}/screenshots/finalcif_loops2.png +0 -0
- {finalcif-158 → finalcif-159}/screenshots/finalcif_main.png +0 -0
- {finalcif-158 → finalcif-159}/screenshots/finalcif_report.png +0 -0
- {finalcif-158 → finalcif-159}/screenshots/finalcif_responses.png +0 -0
- {finalcif-158 → finalcif-159}/update.exe +0 -0
- {finalcif-158 → finalcif-159}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: finalcif
|
|
3
|
-
Version:
|
|
3
|
+
Version: 159
|
|
4
4
|
Summary: CIF file editor
|
|
5
5
|
Project-URL: Homepage, https://dkratzert.de/finalcif.html
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/dkratzert/FinalCif/issues
|
|
@@ -38,7 +38,7 @@ Requires-Dist: urllib3
|
|
|
38
38
|
Requires-Dist: wheel
|
|
39
39
|
Description-Content-Type: text/markdown
|
|
40
40
|
|
|
41
|
-

|
|
42
42
|
[](https://github.com/dkratzert/FinalCif/actions/workflows/python_tests.yml)
|
|
43
43
|

|
|
44
44
|
[](https://repology.org/project/python:finalcif/versions)
|
|
@@ -49,7 +49,7 @@ Description-Content-Type: text/markdown
|
|
|
49
49
|
|
|
50
50
|
# FinalCif
|
|
51
51
|
|
|
52
|
-
FinalCif helps you to get a complete [CIF](https://www.iucr.org/resources/cif) file from a single-
|
|
52
|
+
FinalCif helps you to get a complete [CIF](https://www.iucr.org/resources/cif) file from a single-crystal X-ray diffraction experiment. See here [https://dkratzert.de/finalcif.html](https://dkratzert.de/finalcif.html) for details.
|
|
53
53
|
|
|
54
54
|
For tables from multiple CIF files, you may want to use the program [multitable](https://github.com/dkratzert/multitable).
|
|
55
55
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-

|
|
2
2
|
[](https://github.com/dkratzert/FinalCif/actions/workflows/python_tests.yml)
|
|
3
3
|

|
|
4
4
|
[](https://repology.org/project/python:finalcif/versions)
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
# FinalCif
|
|
11
11
|
|
|
12
|
-
FinalCif helps you to get a complete [CIF](https://www.iucr.org/resources/cif) file from a single-
|
|
12
|
+
FinalCif helps you to get a complete [CIF](https://www.iucr.org/resources/cif) file from a single-crystal X-ray diffraction experiment. See here [https://dkratzert.de/finalcif.html](https://dkratzert.de/finalcif.html) for details.
|
|
13
13
|
|
|
14
14
|
For tables from multiple CIF files, you may want to use the program [multitable](https://github.com/dkratzert/multitable).
|
|
15
15
|
|
|
@@ -16,9 +16,10 @@ from contextlib import suppress
|
|
|
16
16
|
from datetime import datetime
|
|
17
17
|
from math import sin, radians
|
|
18
18
|
from pathlib import Path, WindowsPath
|
|
19
|
-
from typing import cast
|
|
19
|
+
from typing import cast
|
|
20
20
|
|
|
21
21
|
from fastmolwidget.sdm import SDM
|
|
22
|
+
|
|
22
23
|
from finalcif.gui.vzs_viewer import VZSImageViewer
|
|
23
24
|
|
|
24
25
|
warnings.filterwarnings("ignore", category=RuntimeWarning, module="shibokensupport.signature.parser")
|
|
@@ -31,7 +32,7 @@ if hasattr(gemmi, 'set_leak_warnings'):
|
|
|
31
32
|
import requests
|
|
32
33
|
from qtpy import QtCore, QtGui, QtWebEngineWidgets, QtWidgets, compat
|
|
33
34
|
from qtpy.QtCore import Qt, QEvent
|
|
34
|
-
from qtpy.QtWidgets import (QMainWindow, QCheckBox,
|
|
35
|
+
from qtpy.QtWidgets import (QMainWindow, QCheckBox, QApplication,
|
|
35
36
|
QPlainTextEdit, QMessageBox, QScrollBar)
|
|
36
37
|
from gemmi import cif
|
|
37
38
|
|
|
@@ -57,15 +58,15 @@ from finalcif.gui.dialogs import show_update_warning, unable_to_open_message, sh
|
|
|
57
58
|
from finalcif.gui.finalcif_gui_ui import Ui_FinalCifWindow
|
|
58
59
|
from finalcif.gui.import_selector import ImportSelector
|
|
59
60
|
from finalcif.gui.loop_creator import LoopCreator
|
|
60
|
-
from finalcif.gui.loops import Loop, LoopTableModel, MyQTableView
|
|
61
61
|
from finalcif.gui.plaintextedit import MyQPlainTextEdit
|
|
62
62
|
from finalcif.gui.text_value_editor import MyTextTemplateEdit, TextEditItem
|
|
63
|
-
from finalcif.
|
|
63
|
+
from finalcif.cif.vrf_entry import VRFEntry
|
|
64
|
+
from finalcif.gui.vrf_classes import MyVRFContainer
|
|
64
65
|
from finalcif.report.templated_report import ReportFormat
|
|
65
66
|
from finalcif.template.templates import ReportTemplates
|
|
66
67
|
from finalcif.tools.download import MyDownloader
|
|
67
68
|
from finalcif.tools.dsrmath import my_isnumeric
|
|
68
|
-
from finalcif.tools.misc import (next_path, celltxt, to_float,
|
|
69
|
+
from finalcif.tools.misc import (next_path, celltxt, to_float, is_database_number,
|
|
69
70
|
open_file, strip_finalcif_of_name, file_age_in_days)
|
|
70
71
|
from finalcif.tools.options import Options
|
|
71
72
|
from finalcif.tools.platon import PlatonRunner
|
|
@@ -101,7 +102,6 @@ class AppWindow(QMainWindow):
|
|
|
101
102
|
self.sources: dict[str, tuple[str, str | None]] | None = None
|
|
102
103
|
self.cif: CifContainer | None = None
|
|
103
104
|
self.report_picture_path: Path | None = None
|
|
104
|
-
self.loopcreate: LoopCreator | None = None
|
|
105
105
|
self.checkdef: list[str] = []
|
|
106
106
|
self.changes_answer: int = 0
|
|
107
107
|
self.validation_response_forms_list = []
|
|
@@ -113,6 +113,8 @@ class AppWindow(QMainWindow):
|
|
|
113
113
|
self.ui = Ui_FinalCifWindow()
|
|
114
114
|
self.ui.setupUi(self)
|
|
115
115
|
self.ui.page_MainTable.setParent(self.ui.MainStackedWidget)
|
|
116
|
+
# Inject the Author Editor tab (defined in the .ui file) into LoopsPage
|
|
117
|
+
self.ui.loops_page.set_author_editor_tab(self.ui.author_editor_widget)
|
|
116
118
|
self.fixfont = QtGui.QFontDatabase.systemFont(QtGui.QFontDatabase.SystemFont.FixedFont)
|
|
117
119
|
self.ui.shelx_TextEdit.setFont(self.fixfont)
|
|
118
120
|
self.ui.shelx_warn_TextEdit.setFont(self.fixfont)
|
|
@@ -333,7 +335,6 @@ class AppWindow(QMainWindow):
|
|
|
333
335
|
except Exception:
|
|
334
336
|
self.ui.CCDCpushButton.setIcon(qta.icon('fa5s.cloud-upload-alt'))
|
|
335
337
|
self.ui.CODpushButton.setIcon(qta.icon('mdi.upload'))
|
|
336
|
-
self.ui.SavePushButton.setIcon(qta.icon('mdi.content-save'))
|
|
337
338
|
self.ui.revertLoopsPushButton.setIcon(qta.icon('mdi.backup-restore'))
|
|
338
339
|
# Backbuttons:
|
|
339
340
|
self.ui.BackpushButtonDetails.setIcon(qta.icon('mdi.keyboard-backspace'))
|
|
@@ -382,18 +383,17 @@ class AppWindow(QMainWindow):
|
|
|
382
383
|
self.ui.ExploreDirButton.clicked.connect(self.explore_current_dir)
|
|
383
384
|
self.ui.LoopsPushButton.clicked.connect(self._on_go_to_loops_page)
|
|
384
385
|
self.ui.LoopsPushButton.clicked.connect(
|
|
385
|
-
lambda x: self.ui.
|
|
386
|
+
lambda x: self.ui.loops_page.tab_widget.setCurrentIndex(1) if self.ui.loops_page.tab_widget.count() > 0 else None)
|
|
386
387
|
self.ui.LoopsPushButton.clicked.connect(lambda x: self.ui.TemplatesStackedWidget.setCurrentIndex(1))
|
|
387
388
|
self.ui.AuthorEditPushButton.clicked.connect(self._on_go_to_loops_page)
|
|
388
389
|
self.ui.AuthorEditPushButton.clicked.connect(lambda x: self.ui.TemplatesStackedWidget.setCurrentIndex(1))
|
|
389
|
-
self.ui.AuthorEditPushButton.clicked.connect(lambda x: self.ui.
|
|
390
|
+
self.ui.AuthorEditPushButton.clicked.connect(lambda x: self.ui.loops_page.tab_widget.setCurrentIndex(0))
|
|
390
391
|
# checkcif
|
|
391
392
|
self.ui.CheckcifStartButton.clicked.connect(self.open_checkcif_page)
|
|
392
393
|
self.ui.CheckcifButton.clicked.connect(self.do_offline_checkcif)
|
|
393
394
|
self.ui.CheckcifHTMLOnlineButton.clicked.connect(self.do_html_checkcif)
|
|
394
395
|
self.ui.CheckcifPDFOnlineButton.clicked.connect(self.do_pdf_checkcif)
|
|
395
396
|
self.ui.BackFromPlatonPushButton.clicked.connect(self.back_to_main_noload)
|
|
396
|
-
self.ui.SavePushButton.clicked.connect(self.save_responses)
|
|
397
397
|
# open, import
|
|
398
398
|
self.ui.SelectCif_PushButton.clicked.connect(self.load_cif_file)
|
|
399
399
|
self.ui.SaveCifButton.clicked.connect(self.save_cif_and_display)
|
|
@@ -404,8 +404,10 @@ class AppWindow(QMainWindow):
|
|
|
404
404
|
self.ui.cif_main_table.row_deleted.connect(self._deleted_row)
|
|
405
405
|
self.ui.CODpushButton.clicked.connect(self.open_cod_page)
|
|
406
406
|
self.ui.CCDCpushButton.clicked.connect(self._ccdc_deposit)
|
|
407
|
-
self.ui.newLoopPushButton.clicked.connect(self.
|
|
408
|
-
self.ui.
|
|
407
|
+
self.ui.newLoopPushButton.clicked.connect(self.ui.loops_page.go_to_new_loop_page)
|
|
408
|
+
self.ui.loops_page.new_loop_requested.connect(self._on_new_loop_requested)
|
|
409
|
+
self.ui.deleteLoopButton.clicked.connect(self.ui.loops_page.on_delete_current_loop)
|
|
410
|
+
self.ui.revertLoopsPushButton.clicked.connect(self.ui.loops_page.revert_all_loops)
|
|
409
411
|
save_shortcut = QtGui.QShortcut(QtGui.QKeySequence('Ctrl+S'), self)
|
|
410
412
|
save_shortcut.activated.connect(self.save_current_cif_file)
|
|
411
413
|
save_shortcut = QtGui.QShortcut(QtGui.QKeySequence('Ctrl+H'), self)
|
|
@@ -427,8 +429,6 @@ class AppWindow(QMainWindow):
|
|
|
427
429
|
# help
|
|
428
430
|
self.ui.HelpPushButton.clicked.connect(self.show_help)
|
|
429
431
|
self.ui.ReportPicPushButton.clicked.connect(self.select_report_picture)
|
|
430
|
-
# brings the html checkcif in from in order to avoid confusion of an "empty" checkcif report page:
|
|
431
|
-
self.ui.CheckCIFResultsTabWidget.currentChanged.connect(lambda: self.ui.ResponsesTabWidget.setCurrentIndex(0))
|
|
432
432
|
##
|
|
433
433
|
self.ui.SelectCif_LineEdit.returnPressed.connect(self.check_if_file_field_contains_database_number)
|
|
434
434
|
self.ui.fullIucrCheckBox.clicked.connect(self.toggle_hkl_option)
|
|
@@ -473,9 +473,15 @@ class AppWindow(QMainWindow):
|
|
|
473
473
|
return self.cif.finalcif_file_prefixed(prefix='', suffix='-finalcif_changes.cif', force_strip=True)
|
|
474
474
|
|
|
475
475
|
def _on_go_to_loops_page(self) -> None:
|
|
476
|
-
self.
|
|
476
|
+
self.ui.loops_page.load(self.cif)
|
|
477
477
|
self.ui.MainStackedWidget.go_to_loops_page()
|
|
478
478
|
|
|
479
|
+
def _on_new_loop_requested(self) -> None:
|
|
480
|
+
"""Hide loop-management buttons when the LoopCreator tab is active."""
|
|
481
|
+
self.ui.revertLoopsPushButton.hide()
|
|
482
|
+
self.ui.newLoopPushButton.hide()
|
|
483
|
+
self.ui.deleteLoopButton.hide()
|
|
484
|
+
|
|
479
485
|
def export_all_templates(self, filename: Path | None = None) -> None:
|
|
480
486
|
from finalcif.tools.settings import _custom_encoder
|
|
481
487
|
if not filename:
|
|
@@ -660,7 +666,15 @@ class AppWindow(QMainWindow):
|
|
|
660
666
|
text = self.textedit.ui.plainTextEdit.toPlainText()
|
|
661
667
|
if text:
|
|
662
668
|
TextEditItem._num = 1
|
|
663
|
-
|
|
669
|
+
cif_key = self.textedit.cif_key
|
|
670
|
+
# If the template was opened from a VRF widget, write the text into
|
|
671
|
+
# that widget's response field directly (the table cell is spanned).
|
|
672
|
+
if cif_key and cif_key.startswith('_vrf_'):
|
|
673
|
+
vrf_widget = self.ui.cif_main_table.get_vrf_widget(cif_key)
|
|
674
|
+
if vrf_widget is not None:
|
|
675
|
+
vrf_widget.response_text_edit.setPlainText(text)
|
|
676
|
+
else:
|
|
677
|
+
self.ui.cif_main_table.setText(key=cif_key, column=Column.EDIT, txt=text)
|
|
664
678
|
self.ui.MainStackedWidget.got_to_main_page()
|
|
665
679
|
self.textedit.clear_fields()
|
|
666
680
|
else:
|
|
@@ -959,7 +973,7 @@ class AppWindow(QMainWindow):
|
|
|
959
973
|
self.ui.CheckCifLogPlainTextEdit.appendHtml('<b>CheckCIF failed to finish. '
|
|
960
974
|
'Please try it at https://checkcif.iucr.org/ instead.</b>')
|
|
961
975
|
return
|
|
962
|
-
self.checkcif_browser = QtWebEngineWidgets.QWebEngineView(self
|
|
976
|
+
self.checkcif_browser = QtWebEngineWidgets.QWebEngineView(parent=self)
|
|
963
977
|
self.ui.htmlCHeckCifGridLayout.addWidget(self.checkcif_browser)
|
|
964
978
|
url = QtCore.QUrl.fromLocalFile(str(self.htmlfile.resolve()))
|
|
965
979
|
self.ui.MainStackedWidget.go_to_checkcif_page()
|
|
@@ -968,30 +982,65 @@ class AppWindow(QMainWindow):
|
|
|
968
982
|
self.checkcif_browser.setHtml(self.htmlfile.resolve().read_text('utf-8', 'ignore'))
|
|
969
983
|
except FileNotFoundError:
|
|
970
984
|
print(f'{self.htmlfile} not found')
|
|
971
|
-
self.ui.ResponsesTabWidget.setCurrentIndex(0)
|
|
972
985
|
threading.Thread(target=self._display_structure_factor_report, args=(parser,), daemon=True).start()
|
|
973
986
|
# The picture file linked in the html file:
|
|
974
987
|
threading.Thread(target=parser.save_image, args=(self.cif.finalcif_file.with_suffix('.gif'),),
|
|
975
988
|
daemon=True).start()
|
|
976
989
|
self.ui.CheckCifLogPlainTextEdit.appendPlainText('CheckCIF Report finished.')
|
|
977
|
-
|
|
978
|
-
#
|
|
979
|
-
#
|
|
990
|
+
html_entries = parser.response_forms
|
|
991
|
+
# Merge HTML-parsed entries into the main table:
|
|
992
|
+
# - Entries already shown in the main table (source='cif') get their source badge
|
|
993
|
+
# updated to 'checkcif' to indicate they were returned by this run. The existing
|
|
994
|
+
# response text is preserved.
|
|
995
|
+
# - New entries (not yet in the CIF or table) are added as new rows at the top of
|
|
996
|
+
# the main table, marked 'checkcif'.
|
|
980
997
|
a = AlertHelp(self.checkdef)
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
for
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
998
|
+
table = self.ui.cif_main_table
|
|
999
|
+
# Build a lookup of already-saved CIF VRF entries once, outside the loop.
|
|
1000
|
+
existing_by_key = {e.key: e for e in self.cif.get_vrf_entries()}
|
|
1001
|
+
for entry in html_entries:
|
|
1002
|
+
existing_widget = table.get_vrf_widget(entry.key)
|
|
1003
|
+
if existing_widget is not None:
|
|
1004
|
+
# Row already in table (loaded from CIF): update badge to "From CheckCIF"
|
|
1005
|
+
# but keep the user's existing response text.
|
|
1006
|
+
existing_widget.update_source('checkcif')
|
|
1007
|
+
else:
|
|
1008
|
+
# New entry not yet in the CIF: add a row at the top of the table.
|
|
1009
|
+
# Preserve any existing CIF response if the key happens to be in the CIF
|
|
1010
|
+
# block even though it didn't appear in the table (edge-case safety).
|
|
1011
|
+
if entry.key in existing_by_key:
|
|
1012
|
+
entry.response = existing_by_key[entry.key].response
|
|
1013
|
+
insert_pos = self._vrf_insert_position()
|
|
1014
|
+
table.add_row(key=entry.key, position=insert_pos)
|
|
1015
|
+
if entry.key not in self.cif.order:
|
|
1016
|
+
self.cif.order.insert(insert_pos, entry.key)
|
|
1017
|
+
vrf = MyVRFContainer(entry, a.get_help(entry.alert_num), parent=self,
|
|
1018
|
+
is_multi_cif=self.cif.is_multi_cif)
|
|
1019
|
+
vrf.deleted.connect(self._on_vrf_deleted)
|
|
1020
|
+
vrf.template_requested.connect(self._on_vrf_template_requested)
|
|
1021
|
+
self.validation_response_forms_list.append(vrf)
|
|
1022
|
+
table.place_vrf_widget(insert_pos, vrf)
|
|
1023
|
+
if html_entries:
|
|
1024
|
+
n = len(html_entries)
|
|
1025
|
+
form_noun = 'form' if n == 1 else 'forms'
|
|
1026
|
+
self.ui.CheckCifLogPlainTextEdit.appendHtml(
|
|
1027
|
+
f'<br><b>{n} validation response forms {form_noun} added to the main table.</b>')
|
|
1028
|
+
else:
|
|
1029
|
+
self.ui.CheckCifLogPlainTextEdit.appendHtml(
|
|
1030
|
+
'<br><b>No level A, B or C alerts require a response.</b>')
|
|
1031
|
+
|
|
1032
|
+
def _vrf_insert_position(self) -> int:
|
|
1033
|
+
"""Return the row index just after the last existing ``_vrf_*`` row in the main table.
|
|
1034
|
+
|
|
1035
|
+
New VRF rows added during a CheckCIF run are inserted here so that all
|
|
1036
|
+
VRF entries remain grouped at the top of the table.
|
|
1037
|
+
"""
|
|
1038
|
+
keys = self.ui.cif_main_table.vheaderitems
|
|
1039
|
+
pos = 0
|
|
1040
|
+
for i, k in enumerate(keys):
|
|
1041
|
+
if k.startswith('_vrf_'):
|
|
1042
|
+
pos = i + 1
|
|
1043
|
+
return pos
|
|
995
1044
|
|
|
996
1045
|
def _display_structure_factor_report(self, parser: MyHTMLParser) -> None:
|
|
997
1046
|
self.ui.ckf_textedit.setPlainText(parser.get_ckf())
|
|
@@ -1041,43 +1090,65 @@ class AppWindow(QMainWindow):
|
|
|
1041
1090
|
else:
|
|
1042
1091
|
self.get_checkdef_for_response_forms()
|
|
1043
1092
|
|
|
1044
|
-
def
|
|
1045
|
-
"""
|
|
1046
|
-
|
|
1047
|
-
|
|
1093
|
+
def _write_vrf_data_to_cif(self) -> int:
|
|
1094
|
+
"""Flush inline VRF response text and pending deletions into the CIF document.
|
|
1095
|
+
|
|
1096
|
+
Returns the number of non-empty responses written. This must be called
|
|
1097
|
+
**before** ``self.cif.save()`` so that the CIF file on disk is up-to-date.
|
|
1048
1098
|
"""
|
|
1049
|
-
current_block = self.ui.datanameComboBox.currentIndex()
|
|
1050
|
-
if not self.validation_response_forms_list:
|
|
1051
|
-
return
|
|
1052
1099
|
n = 0
|
|
1053
1100
|
for response_row in self.validation_response_forms_list:
|
|
1054
1101
|
response_txt = response_row.response_text_edit.toPlainText()
|
|
1055
1102
|
if not response_txt:
|
|
1056
|
-
# No response was written
|
|
1057
1103
|
continue
|
|
1058
1104
|
n += 1
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
v.data_name = response_row.form['data_name']
|
|
1064
|
-
for block in self.cif.doc:
|
|
1065
|
-
if block.name == v.data_name:
|
|
1066
|
-
block.set_pair(v.key, quote(utf8_to_str(v.value)))
|
|
1067
|
-
self.save_current_cif_file()
|
|
1068
|
-
self.load_cif_file(self.cif.finalcif_file, current_block, load_changes=False)
|
|
1069
|
-
if n:
|
|
1070
|
-
self.ui.CheckCifLogPlainTextEdit.appendPlainText('Forms saved')
|
|
1071
|
-
else:
|
|
1072
|
-
self.ui.CheckCifLogPlainTextEdit.appendPlainText('No forms were filled in.')
|
|
1073
|
-
|
|
1074
|
-
def _switch_to_report(self) -> None:
|
|
1075
|
-
self.ui.ResponsesTabWidget.setCurrentIndex(0)
|
|
1105
|
+
vrf_entry = response_row.vrf_entry
|
|
1106
|
+
vrf_entry.response = response_txt
|
|
1107
|
+
self.cif.block.set_pair(vrf_entry.key, quote(utf8_to_str(vrf_entry.value)))
|
|
1108
|
+
return n
|
|
1076
1109
|
|
|
1077
1110
|
def _pdf_checkcif_finished(self) -> None:
|
|
1078
1111
|
self.ui.CheckcifPDFOnlineButton.setEnabled(True)
|
|
1079
1112
|
self.ui.CheckcifHTMLOnlineButton.setEnabled(True)
|
|
1080
1113
|
|
|
1114
|
+
def _on_vrf_deleted(self, vrf_widget) -> None:
|
|
1115
|
+
"""
|
|
1116
|
+
Handles the ``deleted`` signal emitted by a ``MyVRFContainer`` widget.
|
|
1117
|
+
|
|
1118
|
+
Removes the widget from ``validation_response_forms_list`` and from the
|
|
1119
|
+
main CIF table row. The table's ``row_deleted`` signal then calls
|
|
1120
|
+
``_deleted_row`` which removes the key from the in-memory CIF block; the
|
|
1121
|
+
deletion is written to disk on the next save.
|
|
1122
|
+
"""
|
|
1123
|
+
if vrf_widget in self.validation_response_forms_list:
|
|
1124
|
+
self.validation_response_forms_list.remove(vrf_widget)
|
|
1125
|
+
# Remove the row from the main table (this also emits row_deleted → _deleted_row
|
|
1126
|
+
# which removes the key from the CIF block in memory).
|
|
1127
|
+
table = self.ui.cif_main_table
|
|
1128
|
+
row = table.row_from_key(vrf_widget.vrf_entry.key)
|
|
1129
|
+
table.delete_row(row)
|
|
1130
|
+
|
|
1131
|
+
def _on_vrf_template_requested(self, key: str) -> None:
|
|
1132
|
+
"""
|
|
1133
|
+
Opens the text-snippet template editor for the given VRF *key*.
|
|
1134
|
+
|
|
1135
|
+
The editor is keyed on the alert code portion of the key
|
|
1136
|
+
(e.g. ``_vrf_PLAT307`` regardless of the data-block suffix), so all
|
|
1137
|
+
structures sharing the same alert code share their templates.
|
|
1138
|
+
The current response text from the VRF widget is pre-filled in the
|
|
1139
|
+
editor's preview field so the user can combine it with a snippet.
|
|
1140
|
+
"""
|
|
1141
|
+
alert_code = self.get_vrf_errortype(key)
|
|
1142
|
+
self.textedit.cif_key = key
|
|
1143
|
+
self.textedit.ui.cifKeyLineEdit.setText(alert_code)
|
|
1144
|
+
self.textedit.add_textfields(self.settings.load_settings_list('text_templates', alert_code))
|
|
1145
|
+
# Pre-fill the editor preview with the current response text from the VRF widget.
|
|
1146
|
+
vrf_widget = self.ui.cif_main_table.get_vrf_widget(key)
|
|
1147
|
+
if vrf_widget is not None:
|
|
1148
|
+
current_response = vrf_widget.response_text_edit.toPlainText()
|
|
1149
|
+
self.textedit.ui.plainTextEdit.setPlainText(current_response)
|
|
1150
|
+
self.ui.MainStackedWidget.go_to_text_template_page()
|
|
1151
|
+
|
|
1081
1152
|
def do_pdf_checkcif(self) -> None:
|
|
1082
1153
|
"""
|
|
1083
1154
|
Performs an online checkcif and shows the result as pdf.
|
|
@@ -1339,6 +1410,9 @@ class AppWindow(QMainWindow):
|
|
|
1339
1410
|
if not self.cif:
|
|
1340
1411
|
# No file is opened
|
|
1341
1412
|
return None
|
|
1413
|
+
# Flush VRF response text *before* rename_data_name, because the
|
|
1414
|
+
# rename replaces VRF keys with new names derived from the block name.
|
|
1415
|
+
self._write_vrf_data_to_cif()
|
|
1342
1416
|
if not self.cif.is_multi_cif:
|
|
1343
1417
|
self.cif.rename_data_name(''.join(self.ui.datanameComboBox.currentText().split(' ')))
|
|
1344
1418
|
self.store_data_from_table_rows()
|
|
@@ -1475,7 +1549,9 @@ class AppWindow(QMainWindow):
|
|
|
1475
1549
|
# increases the pont size every time a bit more :)
|
|
1476
1550
|
# size = font.pointSize()
|
|
1477
1551
|
# font.setPointSize(14)
|
|
1478
|
-
|
|
1552
|
+
fixfont = QtGui.QFontDatabase.systemFont(QtGui.QFontDatabase.SystemFont.FixedFont)
|
|
1553
|
+
fixfont.setPointSize(fixfont.pointSize() + 2)
|
|
1554
|
+
doc.setDefaultFont(fixfont)
|
|
1479
1555
|
final_textedit.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap)
|
|
1480
1556
|
final_textedit.setPlainText(self.cif.finalcif_file.read_text(encoding='utf-8', errors='ignore'))
|
|
1481
1557
|
QtCore.QTimer().singleShot(0, lambda: final_textedit.highlighter.setDocument(doc))
|
|
@@ -1484,7 +1560,7 @@ class AppWindow(QMainWindow):
|
|
|
1484
1560
|
"""
|
|
1485
1561
|
Import an additional cif file to the main table.
|
|
1486
1562
|
"""
|
|
1487
|
-
imp_cif: CifContainer
|
|
1563
|
+
imp_cif: CifContainer
|
|
1488
1564
|
if not filename:
|
|
1489
1565
|
filename = cif_file_open_dialog(parent=self, filter="CIF file (*.cif *.pcf *.cif_od *.cfx *.sqf)")
|
|
1490
1566
|
if not filename:
|
|
@@ -1569,8 +1645,8 @@ class AppWindow(QMainWindow):
|
|
|
1569
1645
|
self._load_block(block, load_changes=load_changes)
|
|
1570
1646
|
self.add_data_names_to_combobox()
|
|
1571
1647
|
self.ui.datanameComboBox.setCurrentIndex(block)
|
|
1572
|
-
QtCore.QTimer.singleShot(0, self.ui.cif_main_table.resizeRowsToContents)
|
|
1573
1648
|
self.ui.datanameComboBox.blockSignals(False)
|
|
1649
|
+
QtCore.QTimer.singleShot(500, self.ui.cif_main_table.resizeRowsToContents)
|
|
1574
1650
|
if self.cif.is_multi_cif:
|
|
1575
1651
|
self._flash_block_combobox()
|
|
1576
1652
|
self.cif.set_order_keys(self.ui.cifOrderWidget.order_keys)
|
|
@@ -1613,8 +1689,10 @@ class AppWindow(QMainWindow):
|
|
|
1613
1689
|
self.ui.ckf_textedit.clear()
|
|
1614
1690
|
# Set to empty state before loading:
|
|
1615
1691
|
self.missing_data = set()
|
|
1616
|
-
# clean table
|
|
1692
|
+
# clean table (including any inline VRF widgets) before loading:
|
|
1617
1693
|
self.ui.cif_main_table.delete_content()
|
|
1694
|
+
# reset VRF tracking lists; fill_cif_table repopulates them via inline widgets
|
|
1695
|
+
self.validation_response_forms_list = []
|
|
1618
1696
|
|
|
1619
1697
|
def _load_block(self, index: int, load_changes: bool = True) -> None:
|
|
1620
1698
|
if not self.cif:
|
|
@@ -2098,11 +2176,21 @@ class AppWindow(QMainWindow):
|
|
|
2098
2176
|
# Phase 3 – create widgets (with view repaints suspended)
|
|
2099
2177
|
# ------------------------------------------------------------------
|
|
2100
2178
|
table.setUpdatesEnabled(False)
|
|
2179
|
+
alert_help = AlertHelp(self.checkdef)
|
|
2101
2180
|
try:
|
|
2102
2181
|
for row_num, row_data in enumerate(model_rows):
|
|
2103
2182
|
if row_data.is_separator:
|
|
2104
2183
|
table.add_separation_line(row_num)
|
|
2105
2184
|
self.complete_data_row = row_num
|
|
2185
|
+
elif row_data.key.startswith('_vrf_'):
|
|
2186
|
+
# Show a VRF response-form widget spanning all 3 columns inline.
|
|
2187
|
+
entry = VRFEntry.from_cif_pair(row_data.key, row_data.raw_value)
|
|
2188
|
+
vrf = MyVRFContainer(entry, alert_help.get_help(entry.alert_num),
|
|
2189
|
+
parent=self, is_multi_cif=self.cif.is_multi_cif)
|
|
2190
|
+
vrf.deleted.connect(self._on_vrf_deleted)
|
|
2191
|
+
vrf.template_requested.connect(self._on_vrf_template_requested)
|
|
2192
|
+
self.validation_response_forms_list.append(vrf)
|
|
2193
|
+
table.place_vrf_widget(row_num, vrf)
|
|
2106
2194
|
else:
|
|
2107
2195
|
table.setText(row=row_num, key=row_data.key, column=Column.CIF,
|
|
2108
2196
|
txt=row_data.strval)
|
|
@@ -2140,78 +2228,6 @@ class AppWindow(QMainWindow):
|
|
|
2140
2228
|
self.ui.cif_main_table.setText(key=key, column=Column.DATA, txt=strval)
|
|
2141
2229
|
self.ui.cif_main_table.setText(key=key, column=Column.EDIT, txt=strval)
|
|
2142
2230
|
|
|
2143
|
-
def make_loops_tables(self) -> None:
|
|
2144
|
-
for _ in range(self.ui.LoopsTabWidget.count()):
|
|
2145
|
-
# I use this, so that always the first tab stays.
|
|
2146
|
-
self.ui.LoopsTabWidget.removeTab(1)
|
|
2147
|
-
if self.cif and self.cif.loops:
|
|
2148
|
-
self.add_loops_tables()
|
|
2149
|
-
|
|
2150
|
-
def add_loops_tables(self) -> None:
|
|
2151
|
-
"""
|
|
2152
|
-
Generates a list of tables containing the cif loops.
|
|
2153
|
-
"""
|
|
2154
|
-
# do_not_display = ('_diffrn_refln_index_h')
|
|
2155
|
-
for num, loop in enumerate(self.cif.loops):
|
|
2156
|
-
tags = loop.tags
|
|
2157
|
-
if not tags or len(tags) < 1:
|
|
2158
|
-
continue
|
|
2159
|
-
# if tags[0] in do_not_display:
|
|
2160
|
-
# continue
|
|
2161
|
-
self.new_loop_tab(loop, num, tags)
|
|
2162
|
-
if self.cif.res_file_data:
|
|
2163
|
-
self.add_res_file_to_loops()
|
|
2164
|
-
|
|
2165
|
-
def new_loop_tab(self, loop: gemmi.cif.Loop, num: int, tags: list[str]):
|
|
2166
|
-
loop = Loop(tags, values=grouper(loop.values, loop.width()),
|
|
2167
|
-
parent=self.ui.LoopsTabWidget, block=self.cif.block)
|
|
2168
|
-
self.add_loop_widget(loop, first_tag=tags[0])
|
|
2169
|
-
self.ui.LoopsTabWidget.setTabToolTip(num + 1, tags[0])
|
|
2170
|
-
self.ui.revertLoopsPushButton.clicked.connect(loop.model.revert)
|
|
2171
|
-
|
|
2172
|
-
def add_loop_widget(self, loop: Loop, first_tag: str) -> None:
|
|
2173
|
-
self.ui.LoopsTabWidget.addTab(loop.tableview, cif_to_header_label.get(first_tag) or first_tag)
|
|
2174
|
-
|
|
2175
|
-
def add_res_file_to_loops(self) -> None:
|
|
2176
|
-
textedit = QPlainTextEdit()
|
|
2177
|
-
self.ui.LoopsTabWidget.addTab(textedit, 'SHELX res file')
|
|
2178
|
-
textedit.setPlainText(self.cif.res_file_data[1:-1])
|
|
2179
|
-
doc = textedit.document()
|
|
2180
|
-
doc.setDefaultFont(self.fixfont)
|
|
2181
|
-
textedit.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap)
|
|
2182
|
-
textedit.setReadOnly(True)
|
|
2183
|
-
|
|
2184
|
-
def _go_to_new_loop_page(self) -> None:
|
|
2185
|
-
self.loopcreate = LoopCreator(parent=self, cif=self.cif)
|
|
2186
|
-
self.ui.LoopsTabWidget.addTab(self.loopcreate, 'Create Loops')
|
|
2187
|
-
self.ui.LoopsTabWidget.setCurrentIndex(self.ui.LoopsTabWidget.count() - 1)
|
|
2188
|
-
self.ui.revertLoopsPushButton.hide()
|
|
2189
|
-
self.ui.newLoopPushButton.hide()
|
|
2190
|
-
self.ui.deleteLoopButton.hide()
|
|
2191
|
-
self.loopcreate.saveLoopPushButton.clicked.connect(self.save_new_loop_to_cif)
|
|
2192
|
-
|
|
2193
|
-
def _on_delete_current_loop(self) -> None:
|
|
2194
|
-
current_tab_index = self.ui.LoopsTabWidget.currentIndex()
|
|
2195
|
-
current_table_view: MyQTableView = self.ui.LoopsTabWidget.widget(current_tab_index)
|
|
2196
|
-
try:
|
|
2197
|
-
header_model: LoopTableModel | QtCore.QAbstractItemModel = current_table_view.horizontalHeader().model()
|
|
2198
|
-
except AttributeError:
|
|
2199
|
-
# Not a QTableView
|
|
2200
|
-
return
|
|
2201
|
-
header_item = header_model._header[0]
|
|
2202
|
-
loop: gemmi.cif.Loop = self.cif.block.find_loop(header_item).get_loop()
|
|
2203
|
-
table: gemmi.cif.Table = self.cif.block.find(loop.tags)
|
|
2204
|
-
table.erase()
|
|
2205
|
-
self.ui.LoopsTabWidget.removeTab(current_tab_index)
|
|
2206
|
-
|
|
2207
|
-
def save_new_loop_to_cif(self):
|
|
2208
|
-
if self.loopcreate:
|
|
2209
|
-
loop = self.loopcreate.save_new_loop_to_cif()
|
|
2210
|
-
self.new_loop_tab(loop=loop, num=self.ui.LoopsTabWidget.count(), tags=self.loopcreate.tags)
|
|
2211
|
-
self.ui.LoopsTabWidget.removeTab(self.ui.LoopsTabWidget.count() - 2)
|
|
2212
|
-
self.loopcreate.deleteLater()
|
|
2213
|
-
self.ui.LoopsTabWidget.setCurrentIndex(self.ui.LoopsTabWidget.count() - 1)
|
|
2214
|
-
|
|
2215
2231
|
def add_row(self, key: str, value: str, at_start=False, position: int | None = None) -> None:
|
|
2216
2232
|
"""
|
|
2217
2233
|
Create a empty row at bottom of cif_main_table. This method only fills cif data in the
|
|
@@ -19,6 +19,7 @@ from requests import Response
|
|
|
19
19
|
from requests.exceptions import MissingSchema
|
|
20
20
|
|
|
21
21
|
from finalcif.cif.cif_file_io import CifContainer
|
|
22
|
+
from finalcif.cif.vrf_entry import VRFEntry
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
class CheckCif(QThread):
|
|
@@ -198,37 +199,39 @@ class MyHTMLParser(HTMLParser):
|
|
|
198
199
|
return ''
|
|
199
200
|
|
|
200
201
|
@property
|
|
201
|
-
def response_forms(self) -> list[
|
|
202
|
+
def response_forms(self) -> list[VRFEntry]:
|
|
202
203
|
"""
|
|
203
|
-
:returns
|
|
204
|
-
[
|
|
205
|
-
{'level' : 'PLAT035_ALERT_1_B',
|
|
206
|
-
'name' : '_vrf_PLAT035_DK_zucker2_0m',
|
|
207
|
-
'problem' : '_chemical_absolute_configuration Info Not Given Please Do '
|
|
208
|
-
'! ',
|
|
209
|
-
'alert_num': 'PLAT035'},
|
|
210
|
-
{...},
|
|
211
|
-
]
|
|
204
|
+
:returns a list of VRFEntry instances, one per alert with a validation response form.
|
|
212
205
|
"""
|
|
213
|
-
|
|
214
|
-
|
|
206
|
+
entries = []
|
|
207
|
+
current_key = ''
|
|
208
|
+
current_plat = ''
|
|
209
|
+
current_data = ''
|
|
210
|
+
current_level = ''
|
|
215
211
|
for line in self.vrf.split('\n'):
|
|
216
212
|
if line.startswith('_vrf'):
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
213
|
+
parts = line.split('_')
|
|
214
|
+
current_key = line
|
|
215
|
+
current_plat = parts[2] if len(parts) > 2 else ''
|
|
216
|
+
current_data = line.split('_', 3)[3] if len(parts) > 3 else ''
|
|
217
|
+
current_level = ''
|
|
221
218
|
if line.startswith(';'):
|
|
222
219
|
continue
|
|
223
220
|
if line.startswith('PROBLEM'):
|
|
224
221
|
problem = line[9:]
|
|
225
|
-
single_form.update({'problem': problem})
|
|
226
222
|
for x in self.alert_levels:
|
|
227
|
-
if
|
|
228
|
-
|
|
223
|
+
if current_plat == x[:7]:
|
|
224
|
+
current_level = x
|
|
229
225
|
break
|
|
230
|
-
|
|
231
|
-
|
|
226
|
+
entries.append(VRFEntry(
|
|
227
|
+
key=current_key,
|
|
228
|
+
data_name=current_data,
|
|
229
|
+
problem=problem,
|
|
230
|
+
response='?',
|
|
231
|
+
alert_num=current_plat,
|
|
232
|
+
level=current_level,
|
|
233
|
+
))
|
|
234
|
+
return entries
|
|
232
235
|
|
|
233
236
|
|
|
234
237
|
class AlertHelp:
|
|
@@ -238,7 +241,7 @@ class AlertHelp:
|
|
|
238
241
|
def get_help(self, alert: str) -> str:
|
|
239
242
|
checkdef_help = self._parse_checkdef(alert)
|
|
240
243
|
if not checkdef_help or 'PLAT' not in alert:
|
|
241
|
-
return '
|
|
244
|
+
return ''
|
|
242
245
|
return checkdef_help
|
|
243
246
|
|
|
244
247
|
def _parse_checkdef(self, alert: str) -> str:
|
|
@@ -965,6 +965,22 @@ class CifContainer:
|
|
|
965
965
|
if item.pair is not None:
|
|
966
966
|
yield item.pair
|
|
967
967
|
|
|
968
|
+
def get_vrf_entries(self) -> list:
|
|
969
|
+
"""
|
|
970
|
+
Returns a list of VRFEntry instances for every ``_vrf_*`` key/value pair
|
|
971
|
+
found in the current block. The VRFEntry objects are constructed by
|
|
972
|
+
parsing the semicolon-delimited text value that stores PROBLEM and
|
|
973
|
+
RESPONSE lines.
|
|
974
|
+
"""
|
|
975
|
+
from finalcif.cif.vrf_entry import VRFEntry
|
|
976
|
+
entries = []
|
|
977
|
+
for item in self.block:
|
|
978
|
+
if item.pair is not None:
|
|
979
|
+
key, raw_value = item.pair
|
|
980
|
+
if key.startswith('_vrf_'):
|
|
981
|
+
entries.append(VRFEntry.from_cif_pair(key, raw_value))
|
|
982
|
+
return entries
|
|
983
|
+
|
|
968
984
|
def _is_centrokey(self, key) -> bool:
|
|
969
985
|
"""
|
|
970
986
|
Is True if the kurrent key is only valid
|