finalcif 141__tar.gz → 142__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 (157) hide show
  1. {finalcif-141 → finalcif-142}/.gitignore +1 -0
  2. {finalcif-141 → finalcif-142}/PKG-INFO +1 -2
  3. finalcif-142/finalcif/__init__.py +2 -0
  4. {finalcif-141 → finalcif-142}/finalcif/appwindow.py +38 -32
  5. {finalcif-141 → finalcif-142}/finalcif/cif/cif_file_io.py +38 -14
  6. {finalcif-141 → finalcif-142}/finalcif/gui/finalcif_gui_ui.py +6 -10
  7. {finalcif-141 → finalcif-142}/finalcif/gui/finalcif_gui_ui.ui +10 -11
  8. {finalcif-141 → finalcif-142}/finalcif/report/references.py +0 -1
  9. finalcif-142/finalcif/report/report_text.py +150 -0
  10. {finalcif-141 → finalcif-142}/finalcif/report/tables.py +0 -2
  11. {finalcif-141 → finalcif-142}/finalcif/report/templated_report.py +143 -19
  12. finalcif-142/finalcif/template/report_default.docx +0 -0
  13. finalcif-142/finalcif/template/template_text.docx +0 -0
  14. finalcif-142/finalcif/template/template_without_text.docx +0 -0
  15. {finalcif-141 → finalcif-142}/finalcif/template/templates.py +6 -1
  16. {finalcif-141 → finalcif-142}/finalcif/tools/misc.py +58 -4
  17. {finalcif-141 → finalcif-142}/finalcif/tools/options.py +17 -8
  18. {finalcif-141 → finalcif-142}/requirements.txt +0 -1
  19. finalcif-141/finalcif/__init__.py +0 -2
  20. finalcif-141/finalcif/report/report_text.py +0 -573
  21. finalcif-141/finalcif/template/template_text.docx +0 -0
  22. finalcif-141/finalcif/template/template_without_text.docx +0 -0
  23. {finalcif-141 → finalcif-142}/.gitattributes +0 -0
  24. {finalcif-141 → finalcif-142}/.run/Make Documentation MAC.run.xml +0 -0
  25. {finalcif-141 → finalcif-142}/.run/compile_ui_files.run.xml +0 -0
  26. {finalcif-141 → finalcif-142}/.run/make documentation Windows.run.xml +0 -0
  27. {finalcif-141 → finalcif-142}/CODE_OF_CONDUCT.md +0 -0
  28. {finalcif-141 → finalcif-142}/CONTRIBUTING.md +0 -0
  29. {finalcif-141 → finalcif-142}/Finalcif_installer_win.spec +0 -0
  30. {finalcif-141 → finalcif-142}/Finalcif_linux_onefile.spec +0 -0
  31. {finalcif-141 → finalcif-142}/Finalcif_mac.spec +0 -0
  32. {finalcif-141 → finalcif-142}/Hydrogen_solution_type.cif +0 -0
  33. {finalcif-141 → finalcif-142}/LICENSE +0 -0
  34. {finalcif-141 → finalcif-142}/README.md +0 -0
  35. {finalcif-141 → finalcif-142}/finalcif/app_path.py +0 -0
  36. {finalcif-141 → finalcif-142}/finalcif/cif/__init__.py +0 -0
  37. {finalcif-141 → finalcif-142}/finalcif/cif/all_cif_dicts.py +0 -0
  38. {finalcif-141 → finalcif-142}/finalcif/cif/atoms.py +0 -0
  39. {finalcif-141 → finalcif-142}/finalcif/cif/checkcif/__init__.py +0 -0
  40. {finalcif-141 → finalcif-142}/finalcif/cif/checkcif/checkcif.py +0 -0
  41. {finalcif-141 → finalcif-142}/finalcif/cif/cif_dict_foo.py +0 -0
  42. {finalcif-141 → finalcif-142}/finalcif/cif/cif_order.py +0 -0
  43. {finalcif-141 → finalcif-142}/finalcif/cif/cod/__init__.py +0 -0
  44. {finalcif-141 → finalcif-142}/finalcif/cif/cod/deposit.py +0 -0
  45. {finalcif-141 → finalcif-142}/finalcif/cif/cod/deposit_check.py +0 -0
  46. {finalcif-141 → finalcif-142}/finalcif/cif/cod/deposition_list.py +0 -0
  47. {finalcif-141 → finalcif-142}/finalcif/cif/cod/doi.py +0 -0
  48. {finalcif-141 → finalcif-142}/finalcif/cif/cod/upload.py +0 -0
  49. {finalcif-141 → finalcif-142}/finalcif/cif/cod/website_parser.py +0 -0
  50. {finalcif-141 → finalcif-142}/finalcif/cif/core_dict.py +0 -0
  51. {finalcif-141 → finalcif-142}/finalcif/cif/hkl.py +0 -0
  52. {finalcif-141 → finalcif-142}/finalcif/cif/modulation_dict.py +0 -0
  53. {finalcif-141 → finalcif-142}/finalcif/cif/powder_dict.py +0 -0
  54. {finalcif-141 → finalcif-142}/finalcif/cif/reference.py +0 -0
  55. {finalcif-141 → finalcif-142}/finalcif/cif/restraints_dict.py +0 -0
  56. {finalcif-141 → finalcif-142}/finalcif/cif/text.py +0 -0
  57. {finalcif-141 → finalcif-142}/finalcif/cif/twin_dict.py +0 -0
  58. {finalcif-141 → finalcif-142}/finalcif/datafiles/__init__.py +0 -0
  59. {finalcif-141 → finalcif-142}/finalcif/datafiles/bruker_data.py +0 -0
  60. {finalcif-141 → finalcif-142}/finalcif/datafiles/bruker_frame.py +0 -0
  61. {finalcif-141 → finalcif-142}/finalcif/datafiles/ccdc_mail.py +0 -0
  62. {finalcif-141 → finalcif-142}/finalcif/datafiles/data.py +0 -0
  63. {finalcif-141 → finalcif-142}/finalcif/datafiles/p4p_reader.py +0 -0
  64. {finalcif-141 → finalcif-142}/finalcif/datafiles/sadabs.py +0 -0
  65. {finalcif-141 → finalcif-142}/finalcif/datafiles/saint.py +0 -0
  66. {finalcif-141 → finalcif-142}/finalcif/datafiles/shelx_lst.py +0 -0
  67. {finalcif-141 → finalcif-142}/finalcif/datafiles/utils.py +0 -0
  68. {finalcif-141 → finalcif-142}/finalcif/displaymol/__init__.py +0 -0
  69. {finalcif-141 → finalcif-142}/finalcif/displaymol/molecule2D.py +0 -0
  70. {finalcif-141 → finalcif-142}/finalcif/displaymol/sdm.py +0 -0
  71. {finalcif-141 → finalcif-142}/finalcif/displaymol/vtk_molecule.py +0 -0
  72. {finalcif-141 → finalcif-142}/finalcif/equip_property/__init__.py +0 -0
  73. {finalcif-141 → finalcif-142}/finalcif/equip_property/author_loop_templates.py +0 -0
  74. {finalcif-141 → finalcif-142}/finalcif/equip_property/equipment.py +0 -0
  75. {finalcif-141 → finalcif-142}/finalcif/equip_property/properties.py +0 -0
  76. {finalcif-141 → finalcif-142}/finalcif/equip_property/tools.py +0 -0
  77. {finalcif-141 → finalcif-142}/finalcif/finalcif_start.py +0 -0
  78. {finalcif-141 → finalcif-142}/finalcif/gui/__init__.py +0 -0
  79. {finalcif-141 → finalcif-142}/finalcif/gui/block_combobox.py +0 -0
  80. {finalcif-141 → finalcif-142}/finalcif/gui/combobox.py +0 -0
  81. {finalcif-141 → finalcif-142}/finalcif/gui/custom_classes.py +0 -0
  82. {finalcif-141 → finalcif-142}/finalcif/gui/dialogs.py +0 -0
  83. {finalcif-141 → finalcif-142}/finalcif/gui/edit_button.py +0 -0
  84. {finalcif-141 → finalcif-142}/finalcif/gui/equipmenttable.py +0 -0
  85. {finalcif-141 → finalcif-142}/finalcif/gui/file_editor.py +0 -0
  86. {finalcif-141 → finalcif-142}/finalcif/gui/import_selector.py +0 -0
  87. {finalcif-141 → finalcif-142}/finalcif/gui/import_selector_ui.py +0 -0
  88. {finalcif-141 → finalcif-142}/finalcif/gui/import_selector_ui.ui +0 -0
  89. {finalcif-141 → finalcif-142}/finalcif/gui/loop_creator.py +0 -0
  90. {finalcif-141 → finalcif-142}/finalcif/gui/loop_creator_ui.py +0 -0
  91. {finalcif-141 → finalcif-142}/finalcif/gui/loop_creator_ui.ui +0 -0
  92. {finalcif-141 → finalcif-142}/finalcif/gui/loops.py +0 -0
  93. {finalcif-141 → finalcif-142}/finalcif/gui/mainstackwidget.py +0 -0
  94. {finalcif-141 → finalcif-142}/finalcif/gui/mixins.py +0 -0
  95. {finalcif-141 → finalcif-142}/finalcif/gui/new_key_dialog.py +0 -0
  96. {finalcif-141 → finalcif-142}/finalcif/gui/new_key_dialog_ui.py +0 -0
  97. {finalcif-141 → finalcif-142}/finalcif/gui/new_key_dialog_ui.ui +0 -0
  98. {finalcif-141 → finalcif-142}/finalcif/gui/plaintextedit.py +0 -0
  99. {finalcif-141 → finalcif-142}/finalcif/gui/playground.py +0 -0
  100. {finalcif-141 → finalcif-142}/finalcif/gui/propertytable.py +0 -0
  101. {finalcif-141 → finalcif-142}/finalcif/gui/spell_check_edit.py +0 -0
  102. {finalcif-141 → finalcif-142}/finalcif/gui/text_templates_ui.py +0 -0
  103. {finalcif-141 → finalcif-142}/finalcif/gui/text_templates_ui.ui +0 -0
  104. {finalcif-141 → finalcif-142}/finalcif/gui/text_value_editor.py +0 -0
  105. {finalcif-141 → finalcif-142}/finalcif/gui/validators.py +0 -0
  106. {finalcif-141 → finalcif-142}/finalcif/gui/vrf_classes.py +0 -0
  107. {finalcif-141 → finalcif-142}/finalcif/icon/__init__.py +0 -0
  108. {finalcif-141 → finalcif-142}/finalcif/icon/finalcif.png +0 -0
  109. {finalcif-141 → finalcif-142}/finalcif/icon/finalcif2.ico +0 -0
  110. {finalcif-141 → finalcif-142}/finalcif/icon/finalcif2.png +0 -0
  111. {finalcif-141 → finalcif-142}/finalcif/icon/multitable.ico +0 -0
  112. {finalcif-141 → finalcif-142}/finalcif/icon/multitable.png +0 -0
  113. {finalcif-141 → finalcif-142}/finalcif/icon/multitable.xcf +0 -0
  114. {finalcif-141 → finalcif-142}/finalcif/report/__init__.py +0 -0
  115. {finalcif-141 → finalcif-142}/finalcif/report/archive_report.py +0 -0
  116. {finalcif-141 → finalcif-142}/finalcif/report/gui/__init__.py +0 -0
  117. {finalcif-141 → finalcif-142}/finalcif/report/gui/mainwindow.py +0 -0
  118. {finalcif-141 → finalcif-142}/finalcif/report/gui/mainwindow.ui +0 -0
  119. {finalcif-141 → finalcif-142}/finalcif/report/mtools.py +0 -0
  120. {finalcif-141 → finalcif-142}/finalcif/report/symm.py +0 -0
  121. {finalcif-141 → finalcif-142}/finalcif/template/__init__.py +0 -0
  122. {finalcif-141 → finalcif-142}/finalcif/template/bootstrap/bootstrap.min.css +0 -0
  123. {finalcif-141 → finalcif-142}/finalcif/template/machines/D8_VENTURE.cif +0 -0
  124. {finalcif-141 → finalcif-142}/finalcif/template/mathml2omml.xsl +0 -0
  125. {finalcif-141 → finalcif-142}/finalcif/template/report.tmpl +0 -0
  126. {finalcif-141 → finalcif-142}/finalcif/template/template1.docx +0 -0
  127. {finalcif-141 → finalcif-142}/finalcif/template/template_for_multitable.docx +0 -0
  128. {finalcif-141 → finalcif-142}/finalcif/template/xsl/convert.py +0 -0
  129. {finalcif-141 → finalcif-142}/finalcif/template/xsl/xmltohtml.xsl +0 -0
  130. {finalcif-141 → finalcif-142}/finalcif/tools/__init__.py +0 -0
  131. {finalcif-141 → finalcif-142}/finalcif/tools/chemparse.py +0 -0
  132. {finalcif-141 → finalcif-142}/finalcif/tools/download.py +0 -0
  133. {finalcif-141 → finalcif-142}/finalcif/tools/dsrmath.py +0 -0
  134. {finalcif-141 → finalcif-142}/finalcif/tools/platon.py +0 -0
  135. {finalcif-141 → finalcif-142}/finalcif/tools/pupdate.py +0 -0
  136. {finalcif-141 → finalcif-142}/finalcif/tools/settings.py +0 -0
  137. {finalcif-141 → finalcif-142}/finalcif/tools/shred.py +0 -0
  138. {finalcif-141 → finalcif-142}/finalcif/tools/space_groups.py +0 -0
  139. {finalcif-141 → finalcif-142}/finalcif/tools/spgr_format.py +0 -0
  140. {finalcif-141 → finalcif-142}/finalcif/tools/statusbar.py +0 -0
  141. {finalcif-141 → finalcif-142}/finalcif/tools/sumformula.py +0 -0
  142. {finalcif-141 → finalcif-142}/finalcif.exe +0 -0
  143. {finalcif-141 → finalcif-142}/install_requirements +0 -0
  144. {finalcif-141 → finalcif-142}/install_requirements.bat +0 -0
  145. {finalcif-141 → finalcif-142}/pyproject.toml +0 -0
  146. {finalcif-141 → finalcif-142}/requirements_devel.txt +0 -0
  147. {finalcif-141 → finalcif-142}/requirements_doku.txt +0 -0
  148. {finalcif-141 → finalcif-142}/run_finalcif +0 -0
  149. {finalcif-141 → finalcif-142}/run_finalcif.bat +0 -0
  150. {finalcif-141 → finalcif-142}/screenshots/finalcif_checkcif.png +0 -0
  151. {finalcif-141 → finalcif-142}/screenshots/finalcif_details.png +0 -0
  152. {finalcif-141 → finalcif-142}/screenshots/finalcif_loops.png +0 -0
  153. {finalcif-141 → finalcif-142}/screenshots/finalcif_loops2.png +0 -0
  154. {finalcif-141 → finalcif-142}/screenshots/finalcif_main.png +0 -0
  155. {finalcif-141 → finalcif-142}/screenshots/finalcif_report.png +0 -0
  156. {finalcif-141 → finalcif-142}/screenshots/finalcif_responses.png +0 -0
  157. {finalcif-141 → finalcif-142}/update.exe +0 -0
@@ -220,3 +220,4 @@ test-data/report_1000007-multi-finalcif.docx
220
220
  test.html
221
221
 
222
222
  work/~$test.docx
223
+ tests/examples/work/report_cu_BruecknerJK_153F40_0m-finalcif_pm.docx
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: finalcif
3
- Version: 141
3
+ Version: 142
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
@@ -12,7 +12,6 @@ Classifier: Operating System :: OS Independent
12
12
  Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Topic :: Scientific/Engineering :: Chemistry
14
14
  Requires-Python: >=3.10
15
- Requires-Dist: altgraph
16
15
  Requires-Dist: certifi
17
16
  Requires-Dist: chardet
18
17
  Requires-Dist: crossrefapi
@@ -0,0 +1,2 @@
1
+
2
+ VERSION = 142
@@ -1103,7 +1103,10 @@ class AppWindow(QMainWindow):
1103
1103
  for index in range(self.ui.docxTemplatesListWidget.count()):
1104
1104
  item = self.ui.docxTemplatesListWidget.item(index)
1105
1105
  if item.checkState() == Qt.Checked:
1106
- return item.text()
1106
+ if self.templates.report_from_default_template():
1107
+ return 'finalcif/template/report_default.docx'
1108
+ else:
1109
+ return item.text()
1107
1110
 
1108
1111
  def make_report_tables(self) -> None:
1109
1112
  """
@@ -1122,36 +1125,32 @@ class AppWindow(QMainWindow):
1122
1125
  self.load_cif_file(self.cif.finalcif_file, block=current_block, load_changes=False)
1123
1126
  report_filename = self.cif.finalcif_file_prefixed(prefix='report_', suffix='-finalcif.docx')
1124
1127
  multi_table_document = self.cif.finalcif_file_prefixed(prefix='', suffix='-multitable.docx')
1128
+ self.cif.picometer = self.options.use_picometers
1125
1129
  # The picture after the header:
1126
1130
  if self.report_picture_path:
1127
1131
  picfile = self.report_picture_path
1128
1132
  else:
1129
1133
  picfile = self.cif.finalcif_file.with_suffix('.gif')
1130
1134
  try:
1131
- if self.report_without_template():
1132
- print('Report without templates')
1133
- make_report_from(options=self.options, cif=self.cif,
1134
- output_filename=str(report_filename), picfile=picfile)
1135
+ print('Report with templates')
1136
+ template_path = Path(self.get_checked_templates_list_text())
1137
+ ok = False
1138
+ if template_path.suffix in ('.docx',):
1139
+ t = TemplatedReport(format=ReportFormat.RICHTEXT, options=self.options, cif=self.cif)
1140
+ ok = t.make_templated_docx_report(output_filename=str(report_filename),
1141
+ picfile=picfile,
1142
+ template_path=Path(self.get_checked_templates_list_text()))
1135
1143
  if self.cif.is_multi_cif and self.cif.doc[0].name != 'global':
1136
1144
  make_multi_tables(cif=self.cif, output_filename=str(multi_table_document))
1137
- else:
1138
- print('Report with templates')
1139
- template_path = Path(self.get_checked_templates_list_text())
1140
- ok = False
1141
- if template_path.suffix in ('.docx',):
1142
- t = TemplatedReport(format=ReportFormat.RICHTEXT, options=self.options, cif=self.cif)
1143
- ok = t.make_templated_docx_report(output_filename=str(report_filename),
1144
- picfile=picfile,
1145
- template_path=Path(self.get_checked_templates_list_text()))
1146
- elif template_path.suffix in ('.html', '.tmpl'):
1147
- t = TemplatedReport(format=ReportFormat.HTML, options=self.options, cif=self.cif)
1148
- report_filename = report_filename.with_suffix('.html')
1149
- ok = t.make_templated_html_report(output_filename=str(report_filename),
1150
- picfile=picfile,
1151
- template_path=template_path.parent,
1152
- template_file=template_path.name)
1153
- if not ok:
1154
- return None
1145
+ elif template_path.suffix in ('.html', '.tmpl'):
1146
+ t = TemplatedReport(format=ReportFormat.HTML, options=self.options, cif=self.cif)
1147
+ report_filename = report_filename.with_suffix('.html')
1148
+ ok = t.make_templated_html_report(output_filename=str(report_filename),
1149
+ picfile=picfile,
1150
+ template_path=template_path.parent,
1151
+ template_file=template_path.name)
1152
+ if not ok:
1153
+ return None
1155
1154
  except FileNotFoundError as e:
1156
1155
  if DEBUG:
1157
1156
  raise
@@ -1171,11 +1170,6 @@ class AppWindow(QMainWindow):
1171
1170
  # Save report and other files to a zip file:
1172
1171
  self.zip_report(report_filename)
1173
1172
 
1174
- def report_without_template(self) -> bool:
1175
- """Check whether the report is generated from a template or hard-coded"""
1176
- return self.ui.docxTemplatesListWidget.item(0).checkState() == Qt.CheckState.Checked \
1177
- or not self.ui.docxTemplatesListWidget.currentItem()
1178
-
1179
1173
  def zip_report(self, report_filename: Path) -> None:
1180
1174
  from finalcif.report.archive_report import ArchiveReport
1181
1175
  zipfile = self.cif.finalcif_file.with_suffix('.zip')
@@ -1196,7 +1190,7 @@ class AppWindow(QMainWindow):
1196
1190
  arc.zip.write(filename=multitable, arcname=multitable.name)
1197
1191
 
1198
1192
  def open_report_document(self, report_filename: Path, multi_table_document: Path) -> None:
1199
- if self.cif.is_multi_cif and self.report_without_template():
1193
+ if self.cif.is_multi_cif:
1200
1194
  open_file(multi_table_document)
1201
1195
  open_file(report_filename)
1202
1196
 
@@ -1437,8 +1431,6 @@ class AppWindow(QMainWindow):
1437
1431
  Opens the cif file and fills information into the main table.
1438
1432
  """
1439
1433
  self.ui.datanameComboBox.blockSignals(True)
1440
- # Is also done in block load method
1441
- self._clear_state_before_block_load()
1442
1434
  if not filepath:
1443
1435
  filepath = Path(cif_file_open_dialog(last_dir=self.get_last_workdir()))
1444
1436
  if not filepath.is_file():
@@ -1464,7 +1456,11 @@ class AppWindow(QMainWindow):
1464
1456
  not_ok = e
1465
1457
  if not_ok:
1466
1458
  unable_to_open_message(self, filepath, not_ok)
1467
- return
1459
+ return None
1460
+ if not self.cif.is_valid_structure_cif:
1461
+ show_general_warning(self, "The CIF file you are about to open contains no structure.\n\n"
1462
+ "Use the Import button below to import metadata.")
1463
+ return None
1468
1464
  if not self.cif.chars_ok:
1469
1465
  self.warn_about_bad_cif()
1470
1466
  # Do this only when sure we can load the file:
@@ -1476,6 +1472,16 @@ class AppWindow(QMainWindow):
1476
1472
  self.ui.datanameComboBox.blockSignals(False)
1477
1473
  if self.cif.is_multi_cif:
1478
1474
  self._flash_block_combobox()
1475
+ # Enable to find widgets without parent:
1476
+ # QtCore.QTimer(self).singleShot(1000, self.find_widgets_without_parent)
1477
+
1478
+ def find_widgets_without_parent(self) -> None:
1479
+ print('Finding parents...')
1480
+ all_widgets = app.allWidgets()
1481
+ no_parent_widgets = [widget for widget in all_widgets if widget.parent is None]
1482
+ print(f"Found {len(no_parent_widgets)} widget(s) out of {len(all_widgets)} without parent:")
1483
+ for widget in no_parent_widgets:
1484
+ print(widget, widget.objectName())
1479
1485
 
1480
1486
  def _flash_block_combobox(self):
1481
1487
  orig_pal = self.ui.datanameComboBox.palette()
@@ -20,7 +20,8 @@ from finalcif.cif.cif_order import order, special_keys
20
20
  from finalcif.cif.hkl import HKL, Limit
21
21
  from finalcif.cif.text import utf8_to_str, quote, retranslate_delimiter
22
22
  from finalcif.datafiles.utils import DSRFind
23
- from finalcif.tools.misc import essential_keys, non_centrosymm_keys, isnumeric, grouper, strip_finalcif_of_name
23
+ from finalcif.tools.misc import essential_keys, non_centrosymm_keys, isnumeric, grouper, strip_finalcif_of_name, \
24
+ _angstrom_to_x
24
25
 
25
26
 
26
27
  class GemmiError(Exception):
@@ -40,6 +41,7 @@ class CifContainer():
40
41
  new_block: Create a new block (new file) if a name is given. Otherwise, just
41
42
  the existing document is opened.
42
43
  """
44
+ self.picometer: bool = False
43
45
  self._hkl_file: str = ''
44
46
  self._abs_hkl_details: Dict[str, str] = {}
45
47
  if isinstance(file, str):
@@ -146,6 +148,13 @@ class CifContainer():
146
148
  [x.upper() for x in self.block.find_loop('_atom_site_type_symbol')]))
147
149
  self.check_hkl_min_max()
148
150
 
151
+ @property
152
+ def is_valid_structure_cif(self):
153
+ """
154
+ Checkl wether this CIF contains a structure or just metadata.
155
+ """
156
+ return len(self.atomic_struct.sites) > 0 and self.cell.a
157
+
149
158
  @property
150
159
  def hkl_extra_info(self):
151
160
  if not self._abs_hkl_details:
@@ -665,10 +674,7 @@ class CifContainer():
665
674
  # Do not crash without symmops
666
675
  return False
667
676
  ops = gemmi.GroupOps([gemmi.Op(o) for o in self.symmops])
668
- try:
669
- return ops.is_centric()
670
- except AttributeError:
671
- return ops.is_centrosymmetric()
677
+ return ops.is_centrosymmetric()
672
678
 
673
679
  def atoms(self, without_h: bool = False) -> Generator:
674
680
  """
@@ -689,6 +695,8 @@ class CifContainer():
689
695
  u_eq):
690
696
  if without_h and self.ishydrogen(label):
691
697
  continue
698
+ if self.picometer:
699
+ u_eq = _angstrom_to_x(u_eq, factor=100 ** 2)
692
700
  # 0 1 2 3 4 5 6 7
693
701
  # yield label, type, x, y, z, part, occ, ueq
694
702
  yield atom(label=label, type=type, x=x, y=y, z=z, part=part, occ=occ, u_eq=u_eq)
@@ -721,6 +729,13 @@ class CifContainer():
721
729
  u12 = self.block.find_loop('_atom_site_aniso_U_12')
722
730
  adp = namedtuple('adp', ('label', 'U11', 'U22', 'U33', 'U23', 'U13', 'U12'))
723
731
  for label, u11, u22, u33, u23, u13, u12 in zip(labels, u11, u22, u33, u23, u13, u12):
732
+ if self.picometer:
733
+ u11 = _angstrom_to_x(u11, factor=100 ** 2)
734
+ u22 = _angstrom_to_x(u22, factor=100 ** 2)
735
+ u33 = _angstrom_to_x(u33, factor=100 ** 2)
736
+ u23 = _angstrom_to_x(u23, factor=100 ** 2)
737
+ u13 = _angstrom_to_x(u13, factor=100 ** 2)
738
+ u12 = _angstrom_to_x(u12, factor=100 ** 2)
724
739
  yield adp(label=label, U11=u11, U22=u22, U33=u33, U12=u12, U13=u13, U23=u23)
725
740
 
726
741
  @property
@@ -770,24 +785,29 @@ class CifContainer():
770
785
  publ_loop = self.block.find_loop('_geom_bond_publ_flag')
771
786
  bond = namedtuple('bond', ('label1', 'label2', 'dist', 'symm'))
772
787
  for label1, label2, dist, symm, publ in zip(label1, label2, dist, symm, publ_loop):
773
- if (without_h and (self.ishydrogen(label1) or self.ishydrogen(label2)) or self.yes_not_set(publ)):
788
+ if without_h and (self.ishydrogen(label1) or self.ishydrogen(label2)) or self.yes_not_set(publ):
774
789
  continue
775
790
  else:
791
+ if self.picometer:
792
+ dist = _angstrom_to_x(dist)
776
793
  yield bond(label1=label1, label2=label2, dist=dist, symm=self.checksymm(symm))
777
794
 
778
- def bond_dist(self, pair: str) -> Union[float, None]:
795
+ def bond_dist(self, pair: str) -> Union[str, None]:
779
796
  for p in self.bonds():
780
797
  if f'{p.label1}-{p.label2}' == pair:
781
- return p.dist
798
+ if self.picometer:
799
+ return _angstrom_to_x(p.dist)
800
+ else:
801
+ return p.dist
782
802
  return None
783
803
 
784
- def angle(self, atoms: str) -> Union[float, None]:
804
+ def angle(self, atoms: str) -> Union[str, None]:
785
805
  for p in self.angles():
786
806
  if f'{p.label1}-{p.label2}-{p.label3}' == atoms:
787
807
  return p.angle_val
788
808
  return None
789
809
 
790
- def torsion(self, atoms: str) -> Union[float, None]:
810
+ def torsion(self, atoms: str) -> Union[str, None]:
791
811
  for p in self.torsion_angles():
792
812
  if f'{p.label1}-{p.label2}-{p.label3}-{p.label4}' == atoms:
793
813
  return p.torsang
@@ -803,9 +823,9 @@ class CifContainer():
803
823
  publ_loop = self.block.find_loop('_geom_angle_publ_flag')
804
824
  angle = namedtuple('angle', ('label1', 'label2', 'label3', 'angle_val', 'symm1', 'symm2'))
805
825
  for label1, label2, label3, angle_val, symm1, symm2, publ in \
806
- zip(label1, label2, label3, angle_val, symm1, symm2, publ_loop):
826
+ zip(label1, label2, label3, angle_val, symm1, symm2, publ_loop):
807
827
  if (without_H and (self.ishydrogen(label1) or self.ishydrogen(label2) or
808
- self.ishydrogen(label3)) or (self.yes_not_set(publ))):
828
+ self.ishydrogen(label3)) or (self.yes_not_set(publ))):
809
829
  continue
810
830
  else:
811
831
  yield angle(label1=label1, label2=label2, label3=label3, angle_val=angle_val,
@@ -854,7 +874,7 @@ class CifContainer():
854
874
  symm3,
855
875
  symm4, publ_loop):
856
876
  if (without_h and (self.ishydrogen(label1) or self.ishydrogen(label2)
857
- or self.ishydrogen(label3) or self.ishydrogen(label3)) or self.yes_not_set(publ)):
877
+ or self.ishydrogen(label3) or self.ishydrogen(label3)) or self.yes_not_set(publ)):
858
878
  continue
859
879
  yield tors(label1=label1, label2=label2, label3=label3, label4=label4, torsang=torsang,
860
880
  symm1=self.checksymm(symm1),
@@ -875,9 +895,13 @@ class CifContainer():
875
895
  hydr = namedtuple('HydrogenBond', ('label_d', 'label_h', 'label_a', 'dist_dh', 'dist_ha', 'dist_da',
876
896
  'angle_dha', 'symm'))
877
897
  for label_d, label_h, label_a, dist_dh, dist_ha, dist_da, angle_dha, symm, publ in (
878
- zip(label_d, label_h, label_a, dist_dh, dist_ha, dist_da, angle_dha, symm, publ_loop)):
898
+ zip(label_d, label_h, label_a, dist_dh, dist_ha, dist_da, angle_dha, symm, publ_loop)):
879
899
  if self.yes_not_set(publ):
880
900
  continue
901
+ if self.picometer:
902
+ dist_dh = _angstrom_to_x(dist_dh)
903
+ dist_ha = _angstrom_to_x(dist_ha)
904
+ dist_da = _angstrom_to_x(dist_da)
881
905
  yield hydr(label_d, label_h, label_a, dist_dh, dist_ha, dist_da, angle_dha, self.checksymm(symm))
882
906
 
883
907
  def yes_not_set(self, publ: str):
@@ -13,7 +13,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
13
13
  class Ui_FinalCifWindow(object):
14
14
  def setupUi(self, FinalCifWindow):
15
15
  FinalCifWindow.setObjectName("FinalCifWindow")
16
- FinalCifWindow.resize(1596, 812)
16
+ FinalCifWindow.resize(1596, 860)
17
17
  self.Mainwidget = QtWidgets.QWidget(FinalCifWindow)
18
18
  self.Mainwidget.setObjectName("Mainwidget")
19
19
  self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.Mainwidget)
@@ -242,6 +242,9 @@ class Ui_FinalCifWindow(object):
242
242
  self.HAtomsCheckBox = QtWidgets.QCheckBox(self.groupBox_5)
243
243
  self.HAtomsCheckBox.setObjectName("HAtomsCheckBox")
244
244
  self.gridLayout_26.addWidget(self.HAtomsCheckBox, 1, 0, 1, 2)
245
+ self.UsePicometersCheckBox = QtWidgets.QCheckBox(self.groupBox_5)
246
+ self.UsePicometersCheckBox.setObjectName("UsePicometersCheckBox")
247
+ self.gridLayout_26.addWidget(self.UsePicometersCheckBox, 2, 1, 1, 1)
245
248
  self.verticalLayout_35.addLayout(self.gridLayout_26)
246
249
  self.groupBox_6 = QtWidgets.QGroupBox(self.groupBox_5)
247
250
  sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
@@ -551,7 +554,6 @@ class Ui_FinalCifWindow(object):
551
554
  font.setFamily("Courier New")
552
555
  font.setPointSize(11)
553
556
  font.setBold(True)
554
- font.setWeight(75)
555
557
  self.shelx_warn_TextEdit.setFont(font)
556
558
  self.shelx_warn_TextEdit.setUndoRedoEnabled(False)
557
559
  self.shelx_warn_TextEdit.setLineWrapMode(QtWidgets.QPlainTextEdit.NoWrap)
@@ -589,7 +591,6 @@ class Ui_FinalCifWindow(object):
589
591
  font = QtGui.QFont()
590
592
  font.setBold(False)
591
593
  font.setItalic(False)
592
- font.setWeight(50)
593
594
  self.wR2Label.setFont(font)
594
595
  self.wR2Label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
595
596
  self.wR2Label.setObjectName("wR2Label")
@@ -602,7 +603,6 @@ class Ui_FinalCifWindow(object):
602
603
  font = QtGui.QFont()
603
604
  font.setBold(False)
604
605
  font.setItalic(False)
605
- font.setWeight(50)
606
606
  self.r1Label.setFont(font)
607
607
  self.r1Label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
608
608
  self.r1Label.setObjectName("r1Label")
@@ -630,7 +630,6 @@ class Ui_FinalCifWindow(object):
630
630
  self.completeLabel = QtWidgets.QLabel(self.groupBox_3)
631
631
  font = QtGui.QFont()
632
632
  font.setBold(False)
633
- font.setWeight(50)
634
633
  self.completeLabel.setFont(font)
635
634
  self.completeLabel.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
636
635
  self.completeLabel.setObjectName("completeLabel")
@@ -678,7 +677,6 @@ class Ui_FinalCifWindow(object):
678
677
  self.dataReflnsLabel = QtWidgets.QLabel(self.groupBox_3)
679
678
  font = QtGui.QFont()
680
679
  font.setBold(False)
681
- font.setWeight(50)
682
680
  self.dataReflnsLabel.setFont(font)
683
681
  self.dataReflnsLabel.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
684
682
  self.dataReflnsLabel.setObjectName("dataReflnsLabel")
@@ -745,7 +743,6 @@ class Ui_FinalCifWindow(object):
745
743
  self.rintLabel = QtWidgets.QLabel(self.groupBox_3)
746
744
  font = QtGui.QFont()
747
745
  font.setBold(False)
748
- font.setWeight(50)
749
746
  self.rintLabel.setFont(font)
750
747
  self.rintLabel.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
751
748
  self.rintLabel.setObjectName("rintLabel")
@@ -757,7 +754,6 @@ class Ui_FinalCifWindow(object):
757
754
  self.rsigmaLabel = QtWidgets.QLabel(self.groupBox_3)
758
755
  font = QtGui.QFont()
759
756
  font.setBold(False)
760
- font.setWeight(50)
761
757
  self.rsigmaLabel.setFont(font)
762
758
  self.rsigmaLabel.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
763
759
  self.rsigmaLabel.setObjectName("rsigmaLabel")
@@ -793,7 +789,6 @@ class Ui_FinalCifWindow(object):
793
789
  self.dLabel = QtWidgets.QLabel(self.groupBox_3)
794
790
  font = QtGui.QFont()
795
791
  font.setBold(False)
796
- font.setWeight(50)
797
792
  self.dLabel.setFont(font)
798
793
  self.dLabel.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
799
794
  self.dLabel.setObjectName("dLabel")
@@ -1971,7 +1966,7 @@ class Ui_FinalCifWindow(object):
1971
1966
  self.EquipmentTemplatesListWidget.setToolTip(_translate("FinalCifWindow", "<html><head/><body><p>Each entry can have a list of key/value pairs. For example a Diffractometer model can have a list of features.</p></body></html>"))
1972
1967
  self.NewEquipmentTemplateButton.setText(_translate("FinalCifWindow", "New Template"))
1973
1968
  self.EditEquipmentTemplateButton.setText(_translate("FinalCifWindow", "Edit Template"))
1974
- self.ImportEquipmentTemplateButton.setText(_translate("FinalCifWindow", "Import"))
1969
+ self.ImportEquipmentTemplateButton.setText(_translate("FinalCifWindow", "Import Template"))
1975
1970
  self.EquipmentEditTableWidget.setSortingEnabled(True)
1976
1971
  item = self.EquipmentEditTableWidget.horizontalHeaderItem(0)
1977
1972
  item.setText(_translate("FinalCifWindow", "key"))
@@ -1987,6 +1982,7 @@ class Ui_FinalCifWindow(object):
1987
1982
  self.ReportTextCheckBox.setText(_translate("FinalCifWindow", "No report text in structure report"))
1988
1983
  self.PictureWidthLabel.setText(_translate("FinalCifWindow", "Picture width [cm]"))
1989
1984
  self.HAtomsCheckBox.setText(_translate("FinalCifWindow", "No bonds and angles to hydrogen atoms"))
1985
+ self.UsePicometersCheckBox.setText(_translate("FinalCifWindow", "Use picometers"))
1990
1986
  self.groupBox_6.setTitle(_translate("FinalCifWindow", "Report Templates:"))
1991
1987
  __sortingEnabled = self.docxTemplatesListWidget.isSortingEnabled()
1992
1988
  self.docxTemplatesListWidget.setSortingEnabled(False)
@@ -8,7 +8,7 @@
8
8
  <x>0</x>
9
9
  <y>0</y>
10
10
  <width>1596</width>
11
- <height>812</height>
11
+ <height>860</height>
12
12
  </rect>
13
13
  </property>
14
14
  <property name="windowTitle">
@@ -282,7 +282,7 @@
282
282
  <item>
283
283
  <widget class="QPushButton" name="ImportEquipmentTemplateButton">
284
284
  <property name="text">
285
- <string>Import</string>
285
+ <string>Import Template</string>
286
286
  </property>
287
287
  </widget>
288
288
  </item>
@@ -554,6 +554,13 @@
554
554
  </property>
555
555
  </widget>
556
556
  </item>
557
+ <item row="2" column="1">
558
+ <widget class="QCheckBox" name="UsePicometersCheckBox">
559
+ <property name="text">
560
+ <string>Use picometers</string>
561
+ </property>
562
+ </widget>
563
+ </item>
557
564
  </layout>
558
565
  </item>
559
566
  <item>
@@ -1357,7 +1364,6 @@
1357
1364
  <font>
1358
1365
  <family>Courier New</family>
1359
1366
  <pointsize>11</pointsize>
1360
- <weight>75</weight>
1361
1367
  <bold>true</bold>
1362
1368
  </font>
1363
1369
  </property>
@@ -1424,7 +1430,6 @@
1424
1430
  <widget class="QLabel" name="wR2Label">
1425
1431
  <property name="font">
1426
1432
  <font>
1427
- <weight>50</weight>
1428
1433
  <italic>false</italic>
1429
1434
  <bold>false</bold>
1430
1435
  </font>
@@ -1448,7 +1453,6 @@
1448
1453
  <widget class="QLabel" name="r1Label">
1449
1454
  <property name="font">
1450
1455
  <font>
1451
- <weight>50</weight>
1452
1456
  <italic>false</italic>
1453
1457
  <bold>false</bold>
1454
1458
  </font>
@@ -1506,7 +1510,6 @@
1506
1510
  <widget class="QLabel" name="completeLabel">
1507
1511
  <property name="font">
1508
1512
  <font>
1509
- <weight>50</weight>
1510
1513
  <bold>false</bold>
1511
1514
  </font>
1512
1515
  </property>
@@ -1622,7 +1625,6 @@
1622
1625
  <widget class="QLabel" name="dataReflnsLabel">
1623
1626
  <property name="font">
1624
1627
  <font>
1625
- <weight>50</weight>
1626
1628
  <bold>false</bold>
1627
1629
  </font>
1628
1630
  </property>
@@ -1770,7 +1772,6 @@
1770
1772
  <widget class="QLabel" name="rintLabel">
1771
1773
  <property name="font">
1772
1774
  <font>
1773
- <weight>50</weight>
1774
1775
  <bold>false</bold>
1775
1776
  </font>
1776
1777
  </property>
@@ -1793,7 +1794,6 @@
1793
1794
  <widget class="QLabel" name="rsigmaLabel">
1794
1795
  <property name="font">
1795
1796
  <font>
1796
- <weight>50</weight>
1797
1797
  <bold>false</bold>
1798
1798
  </font>
1799
1799
  </property>
@@ -1867,7 +1867,6 @@
1867
1867
  <widget class="QLabel" name="dLabel">
1868
1868
  <property name="font">
1869
1869
  <font>
1870
- <weight>50</weight>
1871
1870
  <bold>false</bold>
1872
1871
  </font>
1873
1872
  </property>
@@ -4294,7 +4293,7 @@ please add a publication author:</string>
4294
4293
  <extends>QPlainTextEdit</extends>
4295
4294
  <header>finalcif.gui.file_editor.h</header>
4296
4295
  </customwidget>
4297
- <customwidget>
4296
+ <customwidget>
4298
4297
  <class>ComboBoxWithContextMenu</class>
4299
4298
  <extends>QComboBox</extends>
4300
4299
  <header>finalcif.gui.block_combobox.h</header>
@@ -121,7 +121,6 @@ class ReferenceList():
121
121
  paragraph_reflist = document.add_paragraph('', template)
122
122
  paragraph_reflist.add_run(f'[{str(num)}] \t')
123
123
  ref.add_reference(paragraph_reflist)
124
- # paragraph_reflist.add_run('\n')
125
124
 
126
125
  def __repr__(self):
127
126
  return '\n'.join([f'[{num}] {x}' for num, x in enumerate(self._references)])
@@ -0,0 +1,150 @@
1
+ import os
2
+ from builtins import str
3
+ from typing import Union, List, Tuple
4
+
5
+ import gemmi
6
+ from docx import Document
7
+ from docx.oxml.xmlchemy import BaseOxmlElement
8
+ from docx.text.paragraph import Paragraph
9
+ from docx.text.run import Run
10
+ from lxml import etree
11
+ from lxml.etree import XSLTAccessControl
12
+ from shelxfile.atoms.atoms import Atom as SHXAtom
13
+
14
+ from finalcif.app_path import application_path
15
+ from finalcif.cif.cif_file_io import CifContainer
16
+ from finalcif.cif.text import retranslate_delimiter, string_to_utf8
17
+ from finalcif.report import references
18
+ from finalcif.tools.misc import (protected_space, angstrom, zero_width_space, remove_line_endings,
19
+ flatten)
20
+
21
+
22
+ def math_to_word(eq: str) -> BaseOxmlElement:
23
+ """Transform a sympy equation to be printed in word document."""
24
+ tree = etree.fromstring(eq)
25
+ xslt = etree.parse(os.path.join(application_path, 'template/mathml2omml.xsl'))
26
+ acess_control = XSLTAccessControl(read_network=False, write_network=False)
27
+ transform = etree.XSLT(xslt, access_control=acess_control)
28
+ new_dom = transform(tree)
29
+ return new_dom.getroot()
30
+
31
+
32
+ def clean_string(string: str) -> str:
33
+ """
34
+ Removes control characters from a string.
35
+ """
36
+ repl = string.replace('\t', ' ') \
37
+ .replace('\f', ' ') \
38
+ .replace('\0', ' ') \
39
+ .strip(' ') \
40
+ .strip('.')
41
+ return remove_line_endings(repl)
42
+
43
+
44
+ def gstr(string: str) -> str:
45
+ """
46
+ Turn a string into a gemmi string and remove control characters.
47
+ """
48
+ return clean_string(gemmi.cif.as_string(string))
49
+
50
+
51
+ def _get_cooling_device(cif: CifContainer) -> str:
52
+ olx = gstr(cif['_olex2_diffrn_ambient_temperature_device'])
53
+ iucr = gstr(cif['_diffrn_measurement_ambient_temperature_device_make'])
54
+ if olx and iucr:
55
+ return iucr
56
+ if olx:
57
+ return olx
58
+ elif iucr:
59
+ return iucr
60
+ else:
61
+ return ''
62
+
63
+
64
+ class FormatMixin():
65
+
66
+ def bold(self, run: Run):
67
+ r = run.bold = True
68
+ return r
69
+
70
+
71
+
72
+ class SpaceChar():
73
+ def __init__(self, paragraph: Paragraph):
74
+ self.p = paragraph
75
+
76
+ def regular(self) -> None:
77
+ self.p.add_run(' ')
78
+
79
+ def protected(self):
80
+ self.p.add_run(protected_space)
81
+
82
+
83
+ class RefinementDetails():
84
+ def __init__(self, cif: CifContainer, document: Document):
85
+ ph = document.add_paragraph(style='Heading 2')
86
+ ph.add_run(text=fr"Refinement details for {cif.block.name}")
87
+ p = document.add_paragraph()
88
+ try:
89
+ p.style = document.styles['fliesstext']
90
+ except KeyError:
91
+ print('DBG> Text style not found')
92
+ text = ' '.join(cif['_refine_special_details'].splitlines(keepends=False))
93
+ if cif['_olex2_refine_details']:
94
+ text += ' '.join(cif['_olex2_refine_details'].splitlines(keepends=False))
95
+ # Replacing semicolon, because it can damage the CIF:
96
+ text = text.replace(';', '.')
97
+ p.add_run(string_to_utf8(text).strip())
98
+
99
+
100
+ def get_inf_article(next_word: str) -> str:
101
+ if not next_word:
102
+ return 'a'
103
+ voc = 'aeiou'
104
+ return 'an' if next_word[0].lower() in voc else 'a'
105
+
106
+
107
+ def get_distance_unit(picometers: bool) -> str:
108
+ if picometers:
109
+ return 'pm'
110
+ else:
111
+ return angstrom
112
+
113
+
114
+ def get_volume_unit(picometers: bool) -> str:
115
+ if picometers:
116
+ return 'nm'
117
+ else:
118
+ return angstrom
119
+
120
+
121
+ def format_float_with_decimal_places(number: float, places=2) -> str:
122
+ try:
123
+ fnum = float(number)
124
+ return f'{fnum:.{places}f}'
125
+ except ValueError:
126
+ return f'{number}'
127
+
128
+
129
+ def utf8(text: str) -> str:
130
+ """A Jinja2 filter for CIF to utf8"""
131
+ return string_to_utf8(text)
132
+
133
+
134
+ def format_radiation(radiation_type: str) -> list:
135
+ radtype = list(radiation_type.partition("K"))
136
+ if len(radtype) > 2:
137
+ radtype[2] = retranslate_delimiter(radtype[2])
138
+ return radtype
139
+ else:
140
+ return radtype
141
+
142
+
143
+ def make_report_text(cif, document: Document) -> references.ReferenceList:
144
+ paragr = document.add_paragraph()
145
+ try:
146
+ paragr.style = document.styles['fliesstext']
147
+ except KeyError:
148
+ print('DBG> Text style not found')
149
+ ref = references.ReferenceList(paragr)
150
+ return ref
@@ -628,8 +628,6 @@ def add_sum_formula(formula_paragraph: Paragraph, sum_formula: str) -> None:
628
628
  def add_decimal_tab(num_string: str) -> str:
629
629
  """
630
630
  Adds a tab character in front of the decimal point in order to get proper alignment of the tabstops.
631
- >>> add_decimal_tab('-0.123')
632
- '-0\\t.123'
633
631
  """
634
632
  return '\t.'.join(num_string.split('.'))
635
633