finalcif 155__tar.gz → 157__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 (170) hide show
  1. {finalcif-155 → finalcif-157}/.gitattributes +3 -0
  2. {finalcif-155 → finalcif-157}/.gitignore +8 -0
  3. finalcif-157/.python-version +1 -0
  4. {finalcif-155 → finalcif-157}/PKG-INFO +4 -4
  5. finalcif-157/finalcif/__init__.py +2 -0
  6. {finalcif-155 → finalcif-157}/finalcif/appwindow.py +78 -37
  7. {finalcif-155 → finalcif-157}/finalcif/cif/all_cif_dicts.py +5 -0
  8. {finalcif-155 → finalcif-157}/finalcif/cif/checkcif/checkcif.py +4 -1
  9. {finalcif-155 → finalcif-157}/finalcif/cif/cif_order.py +15 -11
  10. {finalcif-155 → finalcif-157}/finalcif/ciforder/order_ui.py +1 -3
  11. {finalcif-155 → finalcif-157}/finalcif/equip_property/author_loop_templates.py +2 -2
  12. {finalcif-155 → finalcif-157}/finalcif/equip_property/properties.py +6 -7
  13. {finalcif-155 → finalcif-157}/finalcif/gui/dialogs.py +12 -2
  14. {finalcif-155 → finalcif-157}/finalcif/gui/file_editor.py +12 -5
  15. {finalcif-155 → finalcif-157}/finalcif/gui/finalcif_gui_ui.py +895 -803
  16. {finalcif-155 → finalcif-157}/finalcif/gui/finalcif_gui_ui.ui +343 -188
  17. {finalcif-155 → finalcif-157}/finalcif/gui/import_selector_ui.py +2 -4
  18. {finalcif-155 → finalcif-157}/finalcif/gui/loop_creator_ui.py +0 -2
  19. {finalcif-155 → finalcif-157}/finalcif/gui/loops.py +0 -1
  20. {finalcif-155 → finalcif-157}/finalcif/gui/new_key_dialog_ui.py +0 -2
  21. finalcif-157/finalcif/gui/syntax_highlighter.py +150 -0
  22. {finalcif-155 → finalcif-157}/finalcif/gui/text_templates_ui.py +0 -2
  23. finalcif-157/finalcif/gui/vzs_viewer.py +182 -0
  24. {finalcif-155 → finalcif-157}/finalcif/report/gui/mainwindow.py +0 -2
  25. {finalcif-155 → finalcif-157}/finalcif/report/references.py +1 -1
  26. {finalcif-155 → finalcif-157}/finalcif/report/templated_report.py +30 -36
  27. {finalcif-155 → finalcif-157}/finalcif/template/report.tmpl +45 -21
  28. finalcif-157/finalcif/template/report_default.docx +0 -0
  29. {finalcif-155 → finalcif-157}/finalcif/tools/misc.py +1 -0
  30. {finalcif-155 → finalcif-157}/finalcif/tools/options.py +12 -4
  31. {finalcif-155 → finalcif-157}/finalcif/tools/shred.py +1 -2
  32. {finalcif-155 → finalcif-157}/finalcif.exe +0 -0
  33. {finalcif-155 → finalcif-157}/platon/README.txt +11 -0
  34. finalcif-157/pylock.toml +892 -0
  35. {finalcif-155 → finalcif-157}/pyproject.toml +16 -6
  36. {finalcif-155 → finalcif-157}/requirements.txt +4 -4
  37. {finalcif-155 → finalcif-157}/uv.lock +290 -141
  38. finalcif-155/.python-version +0 -1
  39. finalcif-155/finalcif/__init__.py +0 -2
  40. finalcif-155/finalcif/template/report_default.docx +0 -0
  41. finalcif-155/install_requirements +0 -9
  42. finalcif-155/install_requirements.bat +0 -13
  43. {finalcif-155 → finalcif-157}/.ruff.toml +0 -0
  44. {finalcif-155 → finalcif-157}/.run/Make Documentation MAC.run.xml +0 -0
  45. {finalcif-155 → finalcif-157}/.run/compile_ui_files.run.xml +0 -0
  46. {finalcif-155 → finalcif-157}/.run/make documentation Windows.run.xml +0 -0
  47. {finalcif-155 → finalcif-157}/CODE_OF_CONDUCT.md +0 -0
  48. {finalcif-155 → finalcif-157}/CONTRIBUTING.md +0 -0
  49. {finalcif-155 → finalcif-157}/Finalcif_installer_win.spec +0 -0
  50. {finalcif-155 → finalcif-157}/Finalcif_linux_onefile.spec +0 -0
  51. {finalcif-155 → finalcif-157}/Finalcif_mac.spec +0 -0
  52. {finalcif-155 → finalcif-157}/Hydrogen_solution_type.cif +0 -0
  53. {finalcif-155 → finalcif-157}/LICENSE +0 -0
  54. {finalcif-155 → finalcif-157}/README.md +0 -0
  55. {finalcif-155 → finalcif-157}/finalcif/app_path.py +0 -0
  56. {finalcif-155 → finalcif-157}/finalcif/cif/__init__.py +0 -0
  57. {finalcif-155 → finalcif-157}/finalcif/cif/atoms.py +0 -0
  58. {finalcif-155 → finalcif-157}/finalcif/cif/checkcif/__init__.py +0 -0
  59. {finalcif-155 → finalcif-157}/finalcif/cif/cif_dict_foo.py +0 -0
  60. {finalcif-155 → finalcif-157}/finalcif/cif/cif_file_io.py +0 -0
  61. {finalcif-155 → finalcif-157}/finalcif/cif/cod/__init__.py +0 -0
  62. {finalcif-155 → finalcif-157}/finalcif/cif/cod/deposit.py +0 -0
  63. {finalcif-155 → finalcif-157}/finalcif/cif/cod/deposit_check.py +0 -0
  64. {finalcif-155 → finalcif-157}/finalcif/cif/cod/deposition_list.py +0 -0
  65. {finalcif-155 → finalcif-157}/finalcif/cif/cod/doi.py +0 -0
  66. {finalcif-155 → finalcif-157}/finalcif/cif/cod/upload.py +0 -0
  67. {finalcif-155 → finalcif-157}/finalcif/cif/cod/website_parser.py +0 -0
  68. {finalcif-155 → finalcif-157}/finalcif/cif/core_dict.py +0 -0
  69. {finalcif-155 → finalcif-157}/finalcif/cif/hkl.py +0 -0
  70. {finalcif-155 → finalcif-157}/finalcif/cif/modulation_dict.py +0 -0
  71. {finalcif-155 → finalcif-157}/finalcif/cif/powder_dict.py +0 -0
  72. {finalcif-155 → finalcif-157}/finalcif/cif/reference.py +0 -0
  73. {finalcif-155 → finalcif-157}/finalcif/cif/restraints_dict.py +0 -0
  74. {finalcif-155 → finalcif-157}/finalcif/cif/text.py +0 -0
  75. {finalcif-155 → finalcif-157}/finalcif/cif/twin_dict.py +0 -0
  76. {finalcif-155 → finalcif-157}/finalcif/ciforder/__init__.py +0 -0
  77. {finalcif-155 → finalcif-157}/finalcif/ciforder/order.py +0 -0
  78. {finalcif-155 → finalcif-157}/finalcif/ciforder/order_ui.ui +0 -0
  79. {finalcif-155 → finalcif-157}/finalcif/datafiles/__init__.py +0 -0
  80. {finalcif-155 → finalcif-157}/finalcif/datafiles/bruker_data.py +0 -0
  81. {finalcif-155 → finalcif-157}/finalcif/datafiles/bruker_frame.py +0 -0
  82. {finalcif-155 → finalcif-157}/finalcif/datafiles/ccdc_mail.py +0 -0
  83. {finalcif-155 → finalcif-157}/finalcif/datafiles/data.py +0 -0
  84. {finalcif-155 → finalcif-157}/finalcif/datafiles/p4p_reader.py +0 -0
  85. {finalcif-155 → finalcif-157}/finalcif/datafiles/sadabs.py +0 -0
  86. {finalcif-155 → finalcif-157}/finalcif/datafiles/saint.py +0 -0
  87. {finalcif-155 → finalcif-157}/finalcif/datafiles/shelx_lst.py +0 -0
  88. {finalcif-155 → finalcif-157}/finalcif/datafiles/utils.py +0 -0
  89. {finalcif-155 → finalcif-157}/finalcif/displaymol/__init__.py +0 -0
  90. {finalcif-155 → finalcif-157}/finalcif/displaymol/molecule2D.py +0 -0
  91. {finalcif-155 → finalcif-157}/finalcif/displaymol/sdm.py +0 -0
  92. {finalcif-155 → finalcif-157}/finalcif/displaymol/vtk_molecule.py +0 -0
  93. {finalcif-155 → finalcif-157}/finalcif/equip_property/__init__.py +0 -0
  94. {finalcif-155 → finalcif-157}/finalcif/equip_property/equipment.py +0 -0
  95. {finalcif-155 → finalcif-157}/finalcif/equip_property/tools.py +0 -0
  96. {finalcif-155 → finalcif-157}/finalcif/finalcif_start.py +0 -0
  97. {finalcif-155 → finalcif-157}/finalcif/gui/__init__.py +0 -0
  98. {finalcif-155 → finalcif-157}/finalcif/gui/block_combobox.py +0 -0
  99. {finalcif-155 → finalcif-157}/finalcif/gui/combobox.py +0 -0
  100. {finalcif-155 → finalcif-157}/finalcif/gui/custom_classes.py +0 -0
  101. {finalcif-155 → finalcif-157}/finalcif/gui/edit_button.py +0 -0
  102. {finalcif-155 → finalcif-157}/finalcif/gui/equipmenttable.py +0 -0
  103. {finalcif-155 → finalcif-157}/finalcif/gui/import_selector.py +0 -0
  104. {finalcif-155 → finalcif-157}/finalcif/gui/import_selector_ui.ui +0 -0
  105. {finalcif-155 → finalcif-157}/finalcif/gui/loop_creator.py +0 -0
  106. {finalcif-155 → finalcif-157}/finalcif/gui/loop_creator_ui.ui +0 -0
  107. {finalcif-155 → finalcif-157}/finalcif/gui/mainstackwidget.py +0 -0
  108. {finalcif-155 → finalcif-157}/finalcif/gui/mixins.py +0 -0
  109. {finalcif-155 → finalcif-157}/finalcif/gui/new_key_dialog.py +0 -0
  110. {finalcif-155 → finalcif-157}/finalcif/gui/new_key_dialog_ui.ui +0 -0
  111. {finalcif-155 → finalcif-157}/finalcif/gui/plaintextedit.py +0 -0
  112. {finalcif-155 → finalcif-157}/finalcif/gui/playground.py +0 -0
  113. {finalcif-155 → finalcif-157}/finalcif/gui/propertytable.py +0 -0
  114. {finalcif-155 → finalcif-157}/finalcif/gui/spell_check_edit.py +0 -0
  115. {finalcif-155 → finalcif-157}/finalcif/gui/text_templates_ui.ui +0 -0
  116. {finalcif-155 → finalcif-157}/finalcif/gui/text_value_editor.py +0 -0
  117. {finalcif-155 → finalcif-157}/finalcif/gui/validators.py +0 -0
  118. {finalcif-155 → finalcif-157}/finalcif/gui/vrf_classes.py +0 -0
  119. {finalcif-155 → finalcif-157}/finalcif/icon/__init__.py +0 -0
  120. {finalcif-155 → finalcif-157}/finalcif/icon/finalcif.png +0 -0
  121. {finalcif-155 → finalcif-157}/finalcif/icon/finalcif2.ico +0 -0
  122. {finalcif-155 → finalcif-157}/finalcif/icon/finalcif2.png +0 -0
  123. {finalcif-155 → finalcif-157}/finalcif/icon/multitable.ico +0 -0
  124. {finalcif-155 → finalcif-157}/finalcif/icon/multitable.png +0 -0
  125. {finalcif-155 → finalcif-157}/finalcif/icon/multitable.xcf +0 -0
  126. {finalcif-155 → finalcif-157}/finalcif/report/__init__.py +0 -0
  127. {finalcif-155 → finalcif-157}/finalcif/report/archive_report.py +0 -0
  128. {finalcif-155 → finalcif-157}/finalcif/report/gui/__init__.py +0 -0
  129. {finalcif-155 → finalcif-157}/finalcif/report/gui/mainwindow.ui +0 -0
  130. {finalcif-155 → finalcif-157}/finalcif/report/mtools.py +0 -0
  131. {finalcif-155 → finalcif-157}/finalcif/report/report_text.py +0 -0
  132. {finalcif-155 → finalcif-157}/finalcif/report/symm.py +0 -0
  133. {finalcif-155 → finalcif-157}/finalcif/report/tables.py +0 -0
  134. {finalcif-155 → finalcif-157}/finalcif/template/__init__.py +0 -0
  135. {finalcif-155 → finalcif-157}/finalcif/template/bootstrap/bootstrap.min.css +0 -0
  136. {finalcif-155 → finalcif-157}/finalcif/template/machines/D8_VENTURE.cif +0 -0
  137. {finalcif-155 → finalcif-157}/finalcif/template/mathml2omml.xsl +0 -0
  138. {finalcif-155 → finalcif-157}/finalcif/template/template1.docx +0 -0
  139. {finalcif-155 → finalcif-157}/finalcif/template/template_for_multitable.docx +0 -0
  140. {finalcif-155 → finalcif-157}/finalcif/template/template_text.docx +0 -0
  141. {finalcif-155 → finalcif-157}/finalcif/template/template_without_text.docx +0 -0
  142. {finalcif-155 → finalcif-157}/finalcif/template/templates.py +0 -0
  143. {finalcif-155 → finalcif-157}/finalcif/template/xsl/convert.py +0 -0
  144. {finalcif-155 → finalcif-157}/finalcif/template/xsl/xmltohtml.xsl +0 -0
  145. {finalcif-155 → finalcif-157}/finalcif/tools/__init__.py +0 -0
  146. {finalcif-155 → finalcif-157}/finalcif/tools/chemparse.py +0 -0
  147. {finalcif-155 → finalcif-157}/finalcif/tools/download.py +0 -0
  148. {finalcif-155 → finalcif-157}/finalcif/tools/dsrmath.py +0 -0
  149. {finalcif-155 → finalcif-157}/finalcif/tools/platon.py +0 -0
  150. {finalcif-155 → finalcif-157}/finalcif/tools/pupdate.py +0 -0
  151. {finalcif-155 → finalcif-157}/finalcif/tools/settings.py +0 -0
  152. {finalcif-155 → finalcif-157}/finalcif/tools/space_groups.py +0 -0
  153. {finalcif-155 → finalcif-157}/finalcif/tools/spgr_format.py +0 -0
  154. {finalcif-155 → finalcif-157}/finalcif/tools/statusbar.py +0 -0
  155. {finalcif-155 → finalcif-157}/finalcif/tools/sumformula.py +0 -0
  156. {finalcif-155 → finalcif-157}/platon/compile_platon.bat +0 -0
  157. {finalcif-155 → finalcif-157}/platon/platon_special.exe +0 -0
  158. {finalcif-155 → finalcif-157}/platon/platon_special.f +0 -0
  159. {finalcif-155 → finalcif-157}/requirements_devel.txt +0 -0
  160. {finalcif-155 → finalcif-157}/requirements_doku.txt +0 -0
  161. {finalcif-155 → finalcif-157}/run_finalcif +0 -0
  162. {finalcif-155 → finalcif-157}/run_finalcif.bat +0 -0
  163. {finalcif-155 → finalcif-157}/screenshots/finalcif_checkcif.png +0 -0
  164. {finalcif-155 → finalcif-157}/screenshots/finalcif_details.png +0 -0
  165. {finalcif-155 → finalcif-157}/screenshots/finalcif_loops.png +0 -0
  166. {finalcif-155 → finalcif-157}/screenshots/finalcif_loops2.png +0 -0
  167. {finalcif-155 → finalcif-157}/screenshots/finalcif_main.png +0 -0
  168. {finalcif-155 → finalcif-157}/screenshots/finalcif_report.png +0 -0
  169. {finalcif-155 → finalcif-157}/screenshots/finalcif_responses.png +0 -0
  170. {finalcif-155 → finalcif-157}/update.exe +0 -0
@@ -6,3 +6,6 @@ FinalCif-v* filter=lfs diff=lfs merge=lfs -text
6
6
  FinalCif-setup* filter=lfs diff=lfs merge=lfs -text
7
7
 
8
8
 
9
+ *.f linguist-detectable=false
10
+ *.html linguist-detectable=false
11
+ *.js linguist-detectable=false
@@ -227,3 +227,11 @@ tests/examples/work/cu_BruecknerJK_153F40_0m.lxt
227
227
  finalcif_keys_order.cif
228
228
  !/.python-version
229
229
  /platon/*.mod
230
+ /work/test.aux
231
+ /work/test.pdf
232
+ /work/test.synctex.gz
233
+ /work/test.tex
234
+ /tests/examples/work/cu_BruecknerJK_153F40_0m-finalcif-1.zip
235
+ /tests/examples/work/cu_BruecknerJK_153F40_0m-finalcif-2.zip
236
+ /tests/examples/work/cu_BruecknerJK_153F40_0m_video-finalcif.png
237
+ /tests/examples/work/report_cu_BruecknerJK_153F40_0m-finalcif.html
@@ -0,0 +1 @@
1
+ cpython@3.14
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: finalcif
3
- Version: 155
3
+ Version: 157
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
@@ -16,11 +16,11 @@ Requires-Dist: certifi
16
16
  Requires-Dist: chardet
17
17
  Requires-Dist: charset-normalizer
18
18
  Requires-Dist: crossrefapi
19
- Requires-Dist: docxtpl
20
- Requires-Dist: gemmi
19
+ Requires-Dist: docxtpl[subdoc]>=0.20.2
20
+ Requires-Dist: gemmi>=0.7.5
21
21
  Requires-Dist: hatchling
22
22
  Requires-Dist: html2text
23
- Requires-Dist: lxml
23
+ Requires-Dist: lxml==6.0.2
24
24
  Requires-Dist: numpy
25
25
  Requires-Dist: packaging
26
26
  Requires-Dist: pefile
@@ -0,0 +1,2 @@
1
+
2
+ VERSION = 157
@@ -5,14 +5,21 @@
5
5
  # and you think this stuff is worth it, you can buy me a beer in return.
6
6
  # ----------------------------------------------------------------------------
7
7
  import os
8
+ import pickle
8
9
  import subprocess
9
10
  import sys
10
11
  import threading
11
12
  import time
13
+ import warnings
12
14
  from contextlib import suppress
13
15
  from datetime import datetime
14
16
  from math import sin, radians
15
17
  from pathlib import Path, WindowsPath
18
+ from typing import cast
19
+
20
+ from finalcif.gui.vzs_viewer import VZSImageViewer
21
+
22
+ warnings.filterwarnings("ignore", category=RuntimeWarning, module="shibokensupport.signature.parser")
16
23
 
17
24
  import gemmi
18
25
 
@@ -43,7 +50,8 @@ from finalcif.gui.custom_classes import Column, MyTableWidgetItem, light_green,
43
50
  white
44
51
  from finalcif.gui.dialogs import show_update_warning, unable_to_open_message, show_general_warning, \
45
52
  cif_file_open_dialog, \
46
- bad_z_message, show_res_checksum_warning, show_hkl_checksum_warning, cif_file_save_dialog, show_yes_now_question
53
+ bad_z_message, show_res_checksum_warning, show_hkl_checksum_warning, cif_file_save_dialog, show_yes_now_question, \
54
+ video_file_open_dialog
47
55
  from finalcif.gui.finalcif_gui_ui import Ui_FinalCifWindow
48
56
  from finalcif.gui.import_selector import ImportSelector
49
57
  from finalcif.gui.loop_creator import LoopCreator
@@ -103,6 +111,10 @@ class AppWindow(QMainWindow):
103
111
  self.ui = Ui_FinalCifWindow()
104
112
  self.ui.setupUi(self)
105
113
  self.ui.page_MainTable.setParent(self.ui.MainStackedWidget)
114
+ self.fixfont = QtGui.QFontDatabase.systemFont(QtGui.QFontDatabase.SystemFont.FixedFont)
115
+ self.ui.shelx_TextEdit.setFont(self.fixfont)
116
+ self.ui.shelx_warn_TextEdit.setFont(self.fixfont)
117
+ self.ui.ckf_textedit.setFont(self.fixfont)
106
118
  self.settings = FinalCifSettings()
107
119
  self.load_fontsize_from_settings()
108
120
  self.options = Options(self.ui, self.settings)
@@ -124,6 +136,9 @@ class AppWindow(QMainWindow):
124
136
  self.ui.TemplatesStackedWidget.setCurrentIndex(0)
125
137
  self.ui.MainStackedWidget.got_to_main_page()
126
138
  self.set_initial_button_states()
139
+ self.video = VZSImageViewer(self)
140
+ self.ui.picturesTabWidget.setCurrentIndex(0)
141
+ self.ui.video_vLayout.addWidget(self.video)
127
142
  if file:
128
143
  self.load_cif_file(file)
129
144
  self.load_recent_cifs_list()
@@ -143,7 +158,9 @@ class AppWindow(QMainWindow):
143
158
  " Spek, A.L. (2020). Acta Cryst. E76, 1-11.\n"
144
159
  " \n"
145
160
  " \n"
146
- " - Recent versions of PLATON may be obtained from: https://platonsoft.nl/xraysoft\n"
161
+ " - Recent versions of PLATON may be obtained from: https://platonsoft.nl/xraysoft\n\n"
162
+ " PLATON is free of charge for Academics.\n"
163
+ " For-profit organisations should contact Anthony L. Spek, a.l.spek@uu.nl for a license."
147
164
  " "
148
165
  )
149
166
  self.set_checkcif_output_font(self.ui.CheckcifPlaintextEdit)
@@ -161,7 +178,7 @@ class AppWindow(QMainWindow):
161
178
  # self.set_font_sizes()
162
179
 
163
180
  def load_fontsize_from_settings(self):
164
- fontsize = self.settings.load_value_of_key('global_font_size')
181
+ fontsize = cast(int, self.settings.load_value_of_key('global_font_size'))
165
182
  if fontsize is not None and fontsize >= 8:
166
183
  self.set_global_font(fontsize)
167
184
  self.ui.textSizeSpinBox.setValue(fontsize)
@@ -428,6 +445,23 @@ class AppWindow(QMainWindow):
428
445
  self.ui.ImportAllTemplatesPushButton.clicked.connect(self.import_all_templates)
429
446
  self.ui.searchMainTableLineEdit.textChanged.connect(self.ui.cif_main_table.search)
430
447
  self.ui.textSizeSpinBox.valueChanged.connect(self.set_global_font)
448
+ # video:
449
+ self.ui.SelectVideo_PushButton.clicked.connect(lambda x: self._select_crystal_video())
450
+ self.ui.videoRightToolButton.clicked.connect(self.video.next)
451
+ self.ui.videoLeftToolButton.clicked.connect(self.video.previous)
452
+ self.ui.setVideoPicturePushButton.clicked.connect(self.set_video_image_for_report)
453
+
454
+ def set_video_image_for_report(self):
455
+ image_filename = self.cif.finalcif_file_prefixed(prefix='', suffix='_video-finalcif.png')
456
+ self.video.save_image(image_filename)
457
+ self.options.video_image = image_filename
458
+
459
+ def _select_crystal_video(self, video_file: Path | None = None) -> None:
460
+ if video_file is None:
461
+ video_file = Path(video_file_open_dialog(parent=self, last_dir=self.get_last_workdir()))
462
+ if video_file is not None and video_file.is_file() and video_file.exists():
463
+ self.ui.videoLineEdit.setText(str(video_file.resolve()))
464
+ self.video.load_file(video_file)
431
465
 
432
466
  @property
433
467
  def finalcif_changes_filename(self):
@@ -437,8 +471,7 @@ class AppWindow(QMainWindow):
437
471
  self.make_loops_tables()
438
472
  self.ui.MainStackedWidget.go_to_loops_page()
439
473
 
440
- def export_all_templates(self, filename: Path | None = None):
441
- import pickle
474
+ def export_all_templates(self, filename: Path | None = None) -> None:
442
475
  if not filename:
443
476
  filename, _ = compat.getsavefilename(parent=self,
444
477
  basedir=str(Path(self.get_last_workdir()).joinpath(
@@ -461,7 +494,7 @@ class AppWindow(QMainWindow):
461
494
  except pickle.PickleError as e:
462
495
  self.status_bar.show_message(f'Saving templates failed: {e!s}')
463
496
 
464
- def import_all_templates(self, filename: Path | None = None):
497
+ def import_all_templates(self, filename: Path | None = None) -> None:
465
498
  import pickle
466
499
  if not filename:
467
500
  filename, _ = compat.getopenfilename(parent=self,
@@ -737,7 +770,7 @@ class AppWindow(QMainWindow):
737
770
  if self.options.track_changes and self.changes_answer == QMessageBox.StandardButton.Yes:
738
771
  self.delete_key_from_changes_cif(key)
739
772
 
740
- def delete_key_from_changes_cif(self, key):
773
+ def delete_key_from_changes_cif(self, key: str) -> None:
741
774
  changes_cif = self.get_changes_cif(self.finalcif_changes_filename)
742
775
  del changes_cif[key]
743
776
  if changes_cif.is_empty():
@@ -921,7 +954,10 @@ class AppWindow(QMainWindow):
921
954
  url = QtCore.QUrl.fromLocalFile(str(self.htmlfile.resolve()))
922
955
  self.ui.MainStackedWidget.go_to_checkcif_page()
923
956
  self.ui.CheckCIFResultsTabWidget.setCurrentIndex(1) # Index 1 is html page
924
- self.checkcif_browser.setHtml(self.htmlfile.resolve().read_text('utf-8', 'ignore'))
957
+ try:
958
+ self.checkcif_browser.setHtml(self.htmlfile.resolve().read_text('utf-8', 'ignore'))
959
+ except FileNotFoundError:
960
+ print(f'{self.htmlfile} not found')
925
961
  self.ui.ResponsesTabWidget.setCurrentIndex(0)
926
962
  threading.Thread(target=self._display_structure_factor_report, args=(parser,)).start()
927
963
  # The picture file linked in the html file:
@@ -1030,7 +1066,6 @@ class AppWindow(QMainWindow):
1030
1066
  def _pdf_checkcif_finished(self) -> None:
1031
1067
  self.ui.CheckcifPDFOnlineButton.setEnabled(True)
1032
1068
  self.ui.CheckcifHTMLOnlineButton.setEnabled(True)
1033
- self.ckf.show_pdf_report()
1034
1069
 
1035
1070
  def do_pdf_checkcif(self) -> None:
1036
1071
  """
@@ -1109,12 +1144,7 @@ class AppWindow(QMainWindow):
1109
1144
 
1110
1145
  def set_checkcif_output_font(self, ccpe: 'QPlainTextEdit') -> None:
1111
1146
  doc = ccpe.document()
1112
- font = doc.defaultFont()
1113
- font.setFamily("Courier New")
1114
- font.setStyleHint(QtGui.QFont.StyleHint.Monospace)
1115
- # app.processEvents()
1116
- # font.setPointSize(14)
1117
- doc.setDefaultFont(font)
1147
+ doc.setDefaultFont(self.fixfont)
1118
1148
 
1119
1149
  def load_recent_file(self, file_index: int) -> None:
1120
1150
  """
@@ -1138,10 +1168,12 @@ class AppWindow(QMainWindow):
1138
1168
  caption='Open a Report Picture')
1139
1169
  self.set_report_picture_path(filename)
1140
1170
 
1141
- def set_report_picture_path(self, filename: str):
1171
+ def set_report_picture_path(self, filename: str) -> None:
1172
+ if not filename:
1173
+ return None
1142
1174
  with suppress(Exception):
1143
1175
  self.report_picture_path = Path(filename)
1144
- if self.report_picture_path.exists() and self.report_picture_path.is_file():
1176
+ if self.report_picture_path and self.report_picture_path.exists() and self.report_picture_path.is_file():
1145
1177
  with suppress(Exception):
1146
1178
  self.set_picture_button_icon()
1147
1179
 
@@ -1181,9 +1213,9 @@ class AppWindow(QMainWindow):
1181
1213
  self.cif.picometer = self.options.use_picometers
1182
1214
  # The picture after the header:
1183
1215
  if self.report_picture_path:
1184
- picfile = self.report_picture_path
1216
+ self.options.structure_figure = self.report_picture_path
1185
1217
  else:
1186
- picfile = self.cif.finalcif_file.with_suffix('.gif')
1218
+ self.options.structure_figure = self.cif.finalcif_file.with_suffix('.gif')
1187
1219
  try:
1188
1220
  print('Report with templates')
1189
1221
  template_path = Path(self.get_checked_templates_list_text())
@@ -1191,7 +1223,6 @@ class AppWindow(QMainWindow):
1191
1223
  if template_path.suffix in ('.docx',):
1192
1224
  t = TemplatedReport(format=ReportFormat.RICHTEXT, options=self.options, cif=self.cif)
1193
1225
  ok = t.make_templated_docx_report(output_filename=str(report_filename),
1194
- picfile=picfile,
1195
1226
  template_path=Path(self.get_checked_templates_list_text()))
1196
1227
  if self.cif.is_multi_cif and self.cif.doc[0].name != 'global':
1197
1228
  make_multi_tables(cif=self.cif, output_filename=str(multi_table_document))
@@ -1199,7 +1230,6 @@ class AppWindow(QMainWindow):
1199
1230
  t = TemplatedReport(format=ReportFormat.HTML, options=self.options, cif=self.cif)
1200
1231
  report_filename = report_filename.with_suffix('.html')
1201
1232
  ok = t.make_templated_html_report(output_filename=str(report_filename),
1202
- picfile=picfile,
1203
1233
  template_path=template_path.parent,
1204
1234
  template_file=template_path.name)
1205
1235
  if not ok:
@@ -1213,10 +1243,11 @@ class AppWindow(QMainWindow):
1213
1243
  return
1214
1244
  except PermissionError:
1215
1245
  if DEBUG:
1246
+ print('dbg> Unable to open report or CIF file')
1216
1247
  raise
1217
- print('Unable to open cif file')
1218
- show_general_warning(self, f'The report document {report_filename.name} could not be opened.\n'
1219
- 'Is the file already opened?')
1248
+ show_general_warning(self,
1249
+ f'The document {report_filename.name} could not be opened to '
1250
+ f'write the report.\nIs the file already opened?')
1220
1251
  return
1221
1252
  if not self.running_inside_unit_test:
1222
1253
  self.open_report_document(report_filename, multi_table_document)
@@ -1266,6 +1297,13 @@ class AppWindow(QMainWindow):
1266
1297
  recent.remove(filename)
1267
1298
  # file has to be str not Path():
1268
1299
  recent.insert(0, filename)
1300
+ for file in recent:
1301
+ try:
1302
+ if not file or not os.path.exists(file):
1303
+ recent.remove(file)
1304
+ continue
1305
+ except Exception:
1306
+ pass
1269
1307
  recent = recent[:10]
1270
1308
  self.settings.settings.setValue('recent_files', recent)
1271
1309
 
@@ -1423,15 +1461,13 @@ class AppWindow(QMainWindow):
1423
1461
  self.ui.MainStackedWidget.go_to_cif_text_page()
1424
1462
  final_textedit = self.ui.FinalCifFilePlainTextEdit
1425
1463
  doc = final_textedit.document()
1426
- font = doc.defaultFont()
1427
- font.setFamily("Courier New")
1428
- font.setStyleHint(QtGui.QFont.StyleHint.Monospace)
1429
1464
  # increases the pont size every time a bit more :)
1430
1465
  # size = font.pointSize()
1431
1466
  # font.setPointSize(14)
1432
- doc.setDefaultFont(font)
1467
+ doc.setDefaultFont(self.fixfont)
1433
1468
  final_textedit.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap)
1434
1469
  final_textedit.setPlainText(self.cif.finalcif_file.read_text(encoding='utf-8', errors='ignore'))
1470
+ QtCore.QTimer().singleShot(0, lambda: final_textedit.highlighter.setDocument(doc))
1435
1471
 
1436
1472
  def import_additional_cif(self, filename: str):
1437
1473
  """
@@ -1496,12 +1532,12 @@ class AppWindow(QMainWindow):
1496
1532
  self.set_path_display_in_file_selector(str(filepath))
1497
1533
  try:
1498
1534
  if not self.able_to_open(filepath):
1499
- return
1535
+ return None
1500
1536
  except (OSError, IndexError):
1501
1537
  print('Something failed during cif file opening...')
1502
1538
  if DEBUG:
1503
1539
  raise
1504
- return
1540
+ return None
1505
1541
  not_ok = None
1506
1542
  try:
1507
1543
  e = None
@@ -1515,14 +1551,14 @@ class AppWindow(QMainWindow):
1515
1551
  if not_ok:
1516
1552
  unable_to_open_message(self, filepath, not_ok)
1517
1553
  return None
1518
- if not self.cif.is_valid_structure_cif and not self.cif.doc.find_block('global'):
1554
+ if not self.cif.is_valid_structure_cif:
1519
1555
  show_general_warning(self, "The CIF file you are about to open contains no structure.\n\n"
1520
1556
  "Use the Import button below to import metadata.")
1521
1557
  return None
1522
1558
  if not self.cif.chars_ok:
1523
1559
  self.warn_about_bad_cif()
1524
1560
  # Do this only when sure we can load the file:
1525
- self.save_current_recent_files_list(filepath)
1561
+ QtCore.QTimer.singleShot(0, lambda: self.save_current_recent_files_list(filepath))
1526
1562
  self._load_block(block, load_changes=load_changes)
1527
1563
  self.add_data_names_to_combobox()
1528
1564
  self.ui.datanameComboBox.setCurrentIndex(block)
@@ -1531,9 +1567,18 @@ class AppWindow(QMainWindow):
1531
1567
  if self.cif.is_multi_cif:
1532
1568
  self._flash_block_combobox()
1533
1569
  self.cif.set_order_keys(self.ui.cifOrderWidget.order_keys)
1570
+ QtCore.QTimer().singleShot(0, self._find_video)
1534
1571
  # Enable to find widgets without parent:
1535
1572
  # QtCore.QTimer(self).singleShot(1000, self.find_widgets_without_parent)
1536
1573
 
1574
+ def _find_video(self) -> None:
1575
+ self.video.reset()
1576
+ self.ui.videoLineEdit.setText('')
1577
+ path = self.cif.fileobj.parent.parent
1578
+ videos = list(path.glob('*.vzs'))
1579
+ if videos:
1580
+ self._select_crystal_video(videos[0])
1581
+
1537
1582
  def find_widgets_without_parent(self) -> None:
1538
1583
  print('Finding parents...')
1539
1584
  all_widgets = app.allWidgets()
@@ -2038,11 +2083,7 @@ class AppWindow(QMainWindow):
2038
2083
  self.ui.LoopsTabWidget.addTab(textedit, 'SHELX res file')
2039
2084
  textedit.setPlainText(self.cif.res_file_data[1:-1])
2040
2085
  doc = textedit.document()
2041
- font = doc.defaultFont()
2042
- font.setFamily("Courier New")
2043
- font.setStyleHint(QtGui.QFont.StyleHint.Monospace)
2044
- # font.setPointSize(14)
2045
- doc.setDefaultFont(font)
2086
+ doc.setDefaultFont(self.fixfont)
2046
2087
  textedit.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap)
2047
2088
  textedit.setReadOnly(True)
2048
2089
 
@@ -105,6 +105,11 @@ additional_keywords = {
105
105
  'The O(CH2CH3)2 solvent molecule (42 electrons) disordred around '
106
106
  'an inverstion center was treated by SQUEEZE. '
107
107
  '<br><p><h4>Type:</h4> string </p>\n',
108
+ '_exptl_bruker_absorpt_correction_T_ratio': '<pre><h2>_exptl_bruker_absorpt_correction_T_ratio</h2>'
109
+ 'SADABS (and other scaling programs) can only determine the RATIO of '
110
+ 'absorpt_correction_Tmin/Tmax, so this value determined by SHELXL is used to '
111
+ 'scale the transmission values from SADABS.</pre>'
112
+ '<br><p><h4>Type:</h4> number (float) </p>\n',
108
113
  }
109
114
 
110
115
  cif_all_dict = {}
@@ -15,6 +15,7 @@ from pathlib import Path
15
15
 
16
16
  import requests
17
17
  from qtpy.QtCore import QThread, Signal
18
+ from requests import Response
18
19
  from requests.exceptions import MissingSchema
19
20
 
20
21
  from finalcif.cif.cif_file_io import CifContainer
@@ -91,8 +92,10 @@ class CheckCif(QThread):
91
92
  with suppress(Exception):
92
93
  # parameter missing_ok=True is only available after 3.8
93
94
  Path('finalcif_checkcif_tmp.cif').unlink()
95
+ if self.pdf:
96
+ self.finished.connect(self._open_pdf_result)
94
97
 
95
- def _do_the_server_request(self, headers: dict, temp_cif: bytes):
98
+ def _do_the_server_request(self, headers: dict, temp_cif: bytes) -> Response | None:
96
99
  req = None
97
100
  try:
98
101
  req = requests.post(self.checkcif_url, files={'file': temp_cif}, data=headers, timeout=900)
@@ -14,6 +14,10 @@ special_keys = ['_iucr_refine_instructions_details',
14
14
  '_refln_F_squared_sigma',
15
15
  '_refln_F_calc',
16
16
  '_refln_F_squared_calc',
17
+
18
+ '_shelx_include_file_name',
19
+ '_shelx_include_file',
20
+ '_shelx_include_file_checksum',
17
21
  ]
18
22
 
19
23
  order = [
@@ -349,19 +353,19 @@ order = [
349
353
  '_geom_details',
350
354
  '_geom_special_details',
351
355
 
352
- '_bruker_diffrn_runs_wavelength',
353
- '_bruker_diffrn_runs_temperature',
354
- '_bruker_diffrn_runs_current',
355
- '_bruker_diffrn_runs_voltage',
356
- '_bruker_diffrn_runs_images',
357
- '_bruker_diffrn_runs_time',
358
- '_bruker_diffrn_runs_width',
359
356
  '_bruker_diffrn_runs_axis',
360
- '_bruker_diffrn_runs_chi',
361
- '_bruker_diffrn_runs_phi',
362
- '_bruker_diffrn_runs_omega',
363
- '_bruker_diffrn_runs_theta',
364
357
  '_bruker_diffrn_runs_distance',
358
+ '_bruker_diffrn_runs_theta',
359
+ '_bruker_diffrn_runs_omega',
360
+ '_bruker_diffrn_runs_phi',
361
+ '_bruker_diffrn_runs_chi',
362
+ '_bruker_diffrn_runs_width',
363
+ '_bruker_diffrn_runs_images',
364
+ '_bruker_diffrn_runs_time',
365
+ '_bruker_diffrn_runs_wavelength',
366
+ '_bruker_diffrn_runs_voltage',
367
+ '_bruker_diffrn_runs_current',
368
+ '_bruker_diffrn_runs_temperature',
365
369
  ]
366
370
 
367
371
 
@@ -113,8 +113,6 @@ class Ui_CifOrderForm(object):
113
113
 
114
114
 
115
115
  self.retranslateUi(CifOrderForm)
116
-
117
- QMetaObject.connectSlotsByName(CifOrderForm)
118
116
  # setupUi
119
117
 
120
118
  def retranslateUi(self, CifOrderForm):
@@ -134,7 +132,7 @@ class Ui_CifOrderForm(object):
134
132
  self.restoreDefaultPushButton.setText(QCoreApplication.translate("CifOrderForm", u"Restore default order", None))
135
133
  self.deleteKeyPushButton.setText(QCoreApplication.translate("CifOrderForm", u"Delete selected key", None))
136
134
  ___qtablewidgetitem = self.cifOrderTableWidget.horizontalHeaderItem(0)
137
- ___qtablewidgetitem.setText(QCoreApplication.translate("CifOrderForm", u"CIF key", None));
135
+ ___qtablewidgetitem.setText(QCoreApplication.translate("CifOrderForm", u"CIF key", None))
138
136
  self.helpTextLabel.setText(QCoreApplication.translate("CifOrderForm", u"Order of CIF keys in the output file. Enabled means they will be forced to remain in the output CIF.", None))
139
137
  # retranslateUi
140
138
 
@@ -381,7 +381,7 @@ class AuthorLoops:
381
381
  authors.append(author_data)
382
382
  return authors
383
383
 
384
- def import_raw_data(self, authors_data: list[Author]):
384
+ def import_raw_data(self, authors_data: list[Author]) -> None:
385
385
  """
386
386
  Import all authors from an external file"""
387
387
  for author in authors_data:
@@ -391,7 +391,7 @@ class AuthorLoops:
391
391
  def authors_list(self) -> list[str]:
392
392
  return self.settings.list_saved_items(property='authors_list')
393
393
 
394
- def contact_author_checked(self, checked: bool):
394
+ def contact_author_checked(self, checked: bool) -> None:
395
395
  """
396
396
  :parameter checked: state of the ContactAuthorCheckBox
397
397
  """
@@ -55,7 +55,7 @@ class Properties(QtCore.QObject):
55
55
  self.app.ui.ExportPropertyButton.clicked.connect(self.export_property_template)
56
56
  self.app.ui.cifKeywordLineEdit.textChanged.connect(self.check_for_duplicates)
57
57
 
58
- def check_for_duplicates(self):
58
+ def check_for_duplicates(self) -> None:
59
59
  key = self.app.ui.cifKeywordLineEdit.text()
60
60
  props = self.export_raw_data()
61
61
  keys = [x['cif_key'] for x in props]
@@ -66,13 +66,12 @@ class Properties(QtCore.QObject):
66
66
  self.lb.setText(f'key {key} already exists')
67
67
  self.lb.move(self.app.ui.cifKeywordLineEdit.mapToGlobal(QtCore.QPoint(15, 25)))
68
68
  self.lb.show()
69
- threading.Thread(target=self.hide_label).start()
69
+ QtCore.QTimer().singleShot(5000, self.hide_label)
70
70
  else:
71
71
  self.app.ui.SavePropertiesButton.setEnabled(True)
72
72
  self.lb.hide()
73
73
 
74
- def hide_label(self):
75
- time.sleep(5)
74
+ def hide_label(self) -> None:
76
75
  self.lb.hide()
77
76
 
78
77
  def show_properties(self) -> None:
@@ -276,9 +275,9 @@ class Properties(QtCore.QObject):
276
275
  return properties_list
277
276
 
278
277
  def import_raw_data(self, properties_list: list[dict]) -> None:
279
- for prop in properties_list:
280
- self.settings.save_settings_list(property='property', name=prop.get("name"),
281
- items=[prop.get('cif_key'), prop.get('data')])
278
+ for property in properties_list:
279
+ self.settings.save_settings_list(property='property', name=property.get("name"),
280
+ items=[property.get('cif_key'), property.get('data')])
282
281
  self.show_properties()
283
282
 
284
283
  @staticmethod
@@ -3,11 +3,10 @@ import os
3
3
  import sys
4
4
  from pathlib import Path
5
5
 
6
+ from finalcif import VERSION
6
7
  from qtpy import QtCore, compat
7
8
  from qtpy.QtWidgets import QMessageBox, QMainWindow, QVBoxLayout, QTextEdit, QPushButton, QFrame
8
9
 
9
- from finalcif import VERSION
10
-
11
10
 
12
11
  def do_update_program(version) -> None:
13
12
  updater_exe = str(Path(__file__).parent.parent.parent.joinpath('update.exe'))
@@ -229,6 +228,17 @@ def cif_file_save_dialog(filename: str, parent=None) -> str:
229
228
  return filename
230
229
 
231
230
 
231
+ def video_file_open_dialog(parent: object = None, filter: str = "Video file (*.vzs; *.jpg)", last_dir='', options=None) -> str:
232
+ filename, _ = compat.getopenfilename(parent=parent,
233
+ caption='Open a crystal video file',
234
+ basedir=last_dir,
235
+ filters=filter,
236
+ selectedfilter=filter,
237
+ options=options
238
+ )
239
+ return filename
240
+
241
+
232
242
  if __name__ == '__main__':
233
243
  from qtpy import QtWidgets
234
244
  from qtpy.QtWidgets import QApplication
@@ -6,6 +6,8 @@ from qtpy.QtCore import QRect, QSize
6
6
  from qtpy.QtGui import QColor, QPainter, QTextFormat
7
7
  from qtpy.QtWidgets import QWidget, QPlainTextEdit, QTextEdit
8
8
 
9
+ from finalcif.gui import syntax_highlighter
10
+
9
11
 
10
12
  class QLineNumberArea(QWidget):
11
13
  def __init__(self, parent: QCodeEditor):
@@ -22,6 +24,7 @@ class QLineNumberArea(QWidget):
22
24
  class QCodeEditor(QPlainTextEdit):
23
25
  def __init__(self, parent=None):
24
26
  super().__init__(parent)
27
+ self.highlighter = syntax_highlighter.CIFSyntaxHighlighter(self)
25
28
  self.lineNumberArea = QLineNumberArea(self)
26
29
  self.blockCountChanged.connect(self.update_line_number_area_width)
27
30
  self.updateRequest.connect(self.update_line_number_area)
@@ -80,9 +83,7 @@ class QCodeEditor(QPlainTextEdit):
80
83
  if block.isVisible() and (bottom >= event.rect().top()):
81
84
  number = f'{block_number + 1} '
82
85
  painter.setPen(QtCore.Qt.GlobalColor.black)
83
- font = painter.font()
84
- font.setFamily("Courier")
85
- font.setStyleHint(QtGui.QFont.StyleHint.Monospace)
86
+ font = QtGui.QFontDatabase.systemFont(QtGui.QFontDatabase.SystemFont.FixedFont)
86
87
  painter.setFont(font)
87
88
  painter.drawText(0, top, self.lineNumberArea.width(), height,
88
89
  QtCore.Qt.AlignmentFlag.AlignRight, number)
@@ -95,13 +96,19 @@ class QCodeEditor(QPlainTextEdit):
95
96
 
96
97
  if __name__ == '__main__':
97
98
  from qtpy.QtWidgets import QApplication
98
-
99
+ import gemmi
99
100
  app = QApplication.instance()
100
101
  if app is None:
101
102
  app = QApplication([])
102
103
  import sys
103
104
 
104
105
  codeEditor = QCodeEditor()
105
- codeEditor.setPlainText('Foo bar')
106
+ codeEditor.setMinimumSize(800, 600)
107
+ font = QtGui.QFontDatabase.systemFont(QtGui.QFontDatabase.SystemFont.FixedFont)
108
+ codeEditor.setFont(font)
109
+ options = gemmi.cif.WriteOptions(gemmi.cif.Style(gemmi.cif.Style.Indent35))
110
+ ciftext = gemmi.cif.read('test-data/DK_Zucker2_0m.cif').sole_block().as_string(options)
111
+ codeEditor.setPlainText(ciftext)
112
+ codeEditor.highlighter.setDocument(codeEditor.document())
106
113
  codeEditor.show()
107
114
  sys.exit(app.exec())