finalcif 127__tar.gz → 129__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 (143) hide show
  1. {finalcif-127 → finalcif-129}/PKG-INFO +1 -1
  2. finalcif-129/finalcif/__init__.py +2 -0
  3. {finalcif-127 → finalcif-129}/finalcif/appwindow.py +101 -96
  4. {finalcif-127 → finalcif-129}/finalcif/cif/checkcif/checkcif.py +32 -17
  5. {finalcif-127 → finalcif-129}/finalcif/cif/cif_file_io.py +10 -8
  6. {finalcif-127 → finalcif-129}/finalcif/displaymol/molecule2D.py +1 -1
  7. {finalcif-127 → finalcif-129}/finalcif/equip_property/properties.py +3 -2
  8. {finalcif-127 → finalcif-129}/finalcif/gui/custom_classes.py +7 -3
  9. {finalcif-127 → finalcif-129}/finalcif/gui/dialogs.py +0 -1
  10. {finalcif-127 → finalcif-129}/finalcif/gui/finalcif_gui_ui.py +23 -14
  11. {finalcif-127 → finalcif-129}/finalcif/gui/finalcif_gui_ui.ui +46 -18
  12. finalcif-129/finalcif/gui/import_selector.py +163 -0
  13. finalcif-129/finalcif/gui/import_selector_ui.py +85 -0
  14. finalcif-129/finalcif/gui/import_selector_ui.ui +115 -0
  15. {finalcif-127 → finalcif-129}/finalcif/gui/loops.py +3 -3
  16. {finalcif-127 → finalcif-129}/finalcif/gui/mainstackwidget.py +4 -1
  17. {finalcif-127 → finalcif-129}/finalcif/gui/plaintextedit.py +21 -7
  18. {finalcif-127 → finalcif-129}/finalcif/report/templated_report.py +18 -14
  19. {finalcif-127 → finalcif-129}/finalcif/tools/misc.py +26 -3
  20. finalcif-129/finalcif.exe +0 -0
  21. finalcif-127/finalcif/__init__.py +0 -2
  22. finalcif-127/finalcif.exe +0 -0
  23. {finalcif-127 → finalcif-129}/.gitattributes +0 -0
  24. {finalcif-127 → finalcif-129}/.gitignore +0 -0
  25. {finalcif-127 → finalcif-129}/.run/Make Documentation MAC.run.xml +0 -0
  26. {finalcif-127 → finalcif-129}/.run/compile_ui_files.run.xml +0 -0
  27. {finalcif-127 → finalcif-129}/.run/make documentation Windows.run.xml +0 -0
  28. {finalcif-127 → finalcif-129}/CODE_OF_CONDUCT.md +0 -0
  29. {finalcif-127 → finalcif-129}/CONTRIBUTING.md +0 -0
  30. {finalcif-127 → finalcif-129}/Finalcif_installer_win.spec +0 -0
  31. {finalcif-127 → finalcif-129}/Finalcif_linux_onefile.spec +0 -0
  32. {finalcif-127 → finalcif-129}/Finalcif_mac.spec +0 -0
  33. {finalcif-127 → finalcif-129}/LICENSE +0 -0
  34. {finalcif-127 → finalcif-129}/README.md +0 -0
  35. {finalcif-127 → finalcif-129}/finalcif/app_path.py +0 -0
  36. {finalcif-127 → finalcif-129}/finalcif/cif/__init__.py +0 -0
  37. {finalcif-127 → finalcif-129}/finalcif/cif/all_cif_dicts.py +0 -0
  38. {finalcif-127 → finalcif-129}/finalcif/cif/atoms.py +0 -0
  39. {finalcif-127 → finalcif-129}/finalcif/cif/checkcif/__init__.py +0 -0
  40. {finalcif-127 → finalcif-129}/finalcif/cif/cif_dict_foo.py +0 -0
  41. {finalcif-127 → finalcif-129}/finalcif/cif/cif_order.py +0 -0
  42. {finalcif-127 → finalcif-129}/finalcif/cif/cod/__init__.py +0 -0
  43. {finalcif-127 → finalcif-129}/finalcif/cif/cod/deposit.py +0 -0
  44. {finalcif-127 → finalcif-129}/finalcif/cif/cod/deposit_check.py +0 -0
  45. {finalcif-127 → finalcif-129}/finalcif/cif/cod/deposition_list.py +0 -0
  46. {finalcif-127 → finalcif-129}/finalcif/cif/cod/doi.py +0 -0
  47. {finalcif-127 → finalcif-129}/finalcif/cif/cod/upload.py +0 -0
  48. {finalcif-127 → finalcif-129}/finalcif/cif/cod/website_parser.py +0 -0
  49. {finalcif-127 → finalcif-129}/finalcif/cif/core_dict.py +0 -0
  50. {finalcif-127 → finalcif-129}/finalcif/cif/hkl.py +0 -0
  51. {finalcif-127 → finalcif-129}/finalcif/cif/modulation_dict.py +0 -0
  52. {finalcif-127 → finalcif-129}/finalcif/cif/powder_dict.py +0 -0
  53. {finalcif-127 → finalcif-129}/finalcif/cif/reference.py +0 -0
  54. {finalcif-127 → finalcif-129}/finalcif/cif/restraints_dict.py +0 -0
  55. {finalcif-127 → finalcif-129}/finalcif/cif/text.py +0 -0
  56. {finalcif-127 → finalcif-129}/finalcif/cif/twin_dict.py +0 -0
  57. {finalcif-127 → finalcif-129}/finalcif/datafiles/__init__.py +0 -0
  58. {finalcif-127 → finalcif-129}/finalcif/datafiles/bruker_data.py +0 -0
  59. {finalcif-127 → finalcif-129}/finalcif/datafiles/bruker_frame.py +0 -0
  60. {finalcif-127 → finalcif-129}/finalcif/datafiles/ccdc_mail.py +0 -0
  61. {finalcif-127 → finalcif-129}/finalcif/datafiles/data.py +0 -0
  62. {finalcif-127 → finalcif-129}/finalcif/datafiles/p4p_reader.py +0 -0
  63. {finalcif-127 → finalcif-129}/finalcif/datafiles/sadabs.py +0 -0
  64. {finalcif-127 → finalcif-129}/finalcif/datafiles/saint.py +0 -0
  65. {finalcif-127 → finalcif-129}/finalcif/datafiles/shelx_lst.py +0 -0
  66. {finalcif-127 → finalcif-129}/finalcif/datafiles/utils.py +0 -0
  67. {finalcif-127 → finalcif-129}/finalcif/displaymol/__init__.py +0 -0
  68. {finalcif-127 → finalcif-129}/finalcif/displaymol/sdm.py +0 -0
  69. {finalcif-127 → finalcif-129}/finalcif/displaymol/vtk_molecule.py +0 -0
  70. {finalcif-127 → finalcif-129}/finalcif/equip_property/__init__.py +0 -0
  71. {finalcif-127 → finalcif-129}/finalcif/equip_property/author_loop_templates.py +0 -0
  72. {finalcif-127 → finalcif-129}/finalcif/equip_property/equipment.py +0 -0
  73. {finalcif-127 → finalcif-129}/finalcif/equip_property/tools.py +0 -0
  74. {finalcif-127 → finalcif-129}/finalcif/finalcif_start.py +0 -0
  75. {finalcif-127 → finalcif-129}/finalcif/gui/__init__.py +0 -0
  76. {finalcif-127 → finalcif-129}/finalcif/gui/combobox.py +0 -0
  77. {finalcif-127 → finalcif-129}/finalcif/gui/equipmenttable.py +0 -0
  78. {finalcif-127 → finalcif-129}/finalcif/gui/file_editor.py +0 -0
  79. {finalcif-127 → finalcif-129}/finalcif/gui/loop_creator.py +0 -0
  80. {finalcif-127 → finalcif-129}/finalcif/gui/loop_creator_ui.py +0 -0
  81. {finalcif-127 → finalcif-129}/finalcif/gui/loop_creator_ui.ui +0 -0
  82. {finalcif-127 → finalcif-129}/finalcif/gui/mixins.py +0 -0
  83. {finalcif-127 → finalcif-129}/finalcif/gui/new_key_dialog.py +0 -0
  84. {finalcif-127 → finalcif-129}/finalcif/gui/new_key_dialog_ui.py +0 -0
  85. {finalcif-127 → finalcif-129}/finalcif/gui/new_key_dialog_ui.ui +0 -0
  86. {finalcif-127 → finalcif-129}/finalcif/gui/playground.py +0 -0
  87. {finalcif-127 → finalcif-129}/finalcif/gui/propertytable.py +0 -0
  88. {finalcif-127 → finalcif-129}/finalcif/gui/spell_check_edit.py +0 -0
  89. {finalcif-127 → finalcif-129}/finalcif/gui/text_templates_ui.py +0 -0
  90. {finalcif-127 → finalcif-129}/finalcif/gui/text_templates_ui.ui +0 -0
  91. {finalcif-127 → finalcif-129}/finalcif/gui/text_value_editor.py +0 -0
  92. {finalcif-127 → finalcif-129}/finalcif/gui/vrf_classes.py +0 -0
  93. {finalcif-127 → finalcif-129}/finalcif/icon/__init__.py +0 -0
  94. {finalcif-127 → finalcif-129}/finalcif/icon/finalcif.png +0 -0
  95. {finalcif-127 → finalcif-129}/finalcif/icon/finalcif2.ico +0 -0
  96. {finalcif-127 → finalcif-129}/finalcif/icon/finalcif2.png +0 -0
  97. {finalcif-127 → finalcif-129}/finalcif/icon/multitable.ico +0 -0
  98. {finalcif-127 → finalcif-129}/finalcif/icon/multitable.png +0 -0
  99. {finalcif-127 → finalcif-129}/finalcif/icon/multitable.xcf +0 -0
  100. {finalcif-127 → finalcif-129}/finalcif/report/__init__.py +0 -0
  101. {finalcif-127 → finalcif-129}/finalcif/report/archive_report.py +0 -0
  102. {finalcif-127 → finalcif-129}/finalcif/report/gui/__init__.py +0 -0
  103. {finalcif-127 → finalcif-129}/finalcif/report/gui/mainwindow.py +0 -0
  104. {finalcif-127 → finalcif-129}/finalcif/report/gui/mainwindow.ui +0 -0
  105. {finalcif-127 → finalcif-129}/finalcif/report/mtools.py +0 -0
  106. {finalcif-127 → finalcif-129}/finalcif/report/references.py +0 -0
  107. {finalcif-127 → finalcif-129}/finalcif/report/report_text.py +0 -0
  108. {finalcif-127 → finalcif-129}/finalcif/report/symm.py +0 -0
  109. {finalcif-127 → finalcif-129}/finalcif/report/tables.py +0 -0
  110. {finalcif-127 → finalcif-129}/finalcif/template/__init__.py +0 -0
  111. {finalcif-127 → finalcif-129}/finalcif/template/mathml2omml.xsl +0 -0
  112. {finalcif-127 → finalcif-129}/finalcif/template/template1.docx +0 -0
  113. {finalcif-127 → finalcif-129}/finalcif/template/template_text.docx +0 -0
  114. {finalcif-127 → finalcif-129}/finalcif/template/template_without_text.docx +0 -0
  115. {finalcif-127 → finalcif-129}/finalcif/template/templates.py +0 -0
  116. {finalcif-127 → finalcif-129}/finalcif/tools/__init__.py +0 -0
  117. {finalcif-127 → finalcif-129}/finalcif/tools/download.py +0 -0
  118. {finalcif-127 → finalcif-129}/finalcif/tools/dsrmath.py +0 -0
  119. {finalcif-127 → finalcif-129}/finalcif/tools/options.py +0 -0
  120. {finalcif-127 → finalcif-129}/finalcif/tools/platon.py +0 -0
  121. {finalcif-127 → finalcif-129}/finalcif/tools/pupdate.py +0 -0
  122. {finalcif-127 → finalcif-129}/finalcif/tools/settings.py +0 -0
  123. {finalcif-127 → finalcif-129}/finalcif/tools/shred.py +0 -0
  124. {finalcif-127 → finalcif-129}/finalcif/tools/space_groups.py +0 -0
  125. {finalcif-127 → finalcif-129}/finalcif/tools/spgr_format.py +0 -0
  126. {finalcif-127 → finalcif-129}/finalcif/tools/statusbar.py +0 -0
  127. {finalcif-127 → finalcif-129}/finalcif/tools/sumformula.py +0 -0
  128. {finalcif-127 → finalcif-129}/install_requirements +0 -0
  129. {finalcif-127 → finalcif-129}/install_requirements.bat +0 -0
  130. {finalcif-127 → finalcif-129}/pyproject.toml +0 -0
  131. {finalcif-127 → finalcif-129}/requirements.txt +0 -0
  132. {finalcif-127 → finalcif-129}/requirements_devel.txt +0 -0
  133. {finalcif-127 → finalcif-129}/requirements_doku.txt +0 -0
  134. {finalcif-127 → finalcif-129}/run_finalcif +0 -0
  135. {finalcif-127 → finalcif-129}/run_finalcif.bat +0 -0
  136. {finalcif-127 → finalcif-129}/screenshots/finalcif_checkcif.png +0 -0
  137. {finalcif-127 → finalcif-129}/screenshots/finalcif_details.png +0 -0
  138. {finalcif-127 → finalcif-129}/screenshots/finalcif_loops.png +0 -0
  139. {finalcif-127 → finalcif-129}/screenshots/finalcif_loops2.png +0 -0
  140. {finalcif-127 → finalcif-129}/screenshots/finalcif_main.png +0 -0
  141. {finalcif-127 → finalcif-129}/screenshots/finalcif_report.png +0 -0
  142. {finalcif-127 → finalcif-129}/screenshots/finalcif_responses.png +0 -0
  143. {finalcif-127 → finalcif-129}/update.exe +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: finalcif
3
- Version: 127
3
+ Version: 129
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
@@ -0,0 +1,2 @@
1
+
2
+ VERSION = 129
@@ -42,8 +42,9 @@ from finalcif.gui.dialogs import show_update_warning, unable_to_open_message, sh
42
42
  cif_file_open_dialog, \
43
43
  bad_z_message, show_res_checksum_warning, show_hkl_checksum_warning, cif_file_save_dialog, show_yes_now_question
44
44
  from finalcif.gui.finalcif_gui_ui import Ui_FinalCifWindow
45
+ from finalcif.gui.import_selector import ImportSelector
45
46
  from finalcif.gui.loop_creator import LoopCreator
46
- from finalcif.gui.loops import Loop
47
+ from finalcif.gui.loops import Loop, LoopTableModel, MyQTableView
47
48
  from finalcif.gui.plaintextedit import MyQPlainTextEdit
48
49
  from finalcif.gui.text_value_editor import MyTextTemplateEdit, TextEditItem
49
50
  from finalcif.gui.vrf_classes import MyVRFContainer, VREF
@@ -53,8 +54,8 @@ from finalcif.report.templated_report import TemplatedReport
53
54
  from finalcif.template.templates import ReportTemplates
54
55
  from finalcif.tools.download import MyDownloader
55
56
  from finalcif.tools.dsrmath import my_isnumeric
56
- from finalcif.tools.misc import next_path, do_not_import_keys, celltxt, to_float, do_not_import_from_stoe_cfx, \
57
- cif_to_header_label, grouper, is_database_number, file_age_in_days, open_file, \
57
+ from finalcif.tools.misc import next_path, celltxt, to_float, cif_to_header_label, grouper, is_database_number, \
58
+ file_age_in_days, open_file, \
58
59
  strip_finalcif_of_name
59
60
  from finalcif.tools.options import Options
60
61
  from finalcif.tools.platon import PlatonRunner
@@ -131,12 +132,11 @@ class AppWindow(QMainWindow):
131
132
  self.connect_signals_and_slots()
132
133
  with suppress(Exception):
133
134
  self.make_button_icons()
134
- self.format_report_button()
135
135
  self.set_font_sizes()
136
136
 
137
137
  @property
138
138
  def running_inside_unit_test(self):
139
- if "PYTEST_CURRENT_TEST" in os.environ:
139
+ if "RUNNING_TEST" in os.environ:
140
140
  if DEBUG:
141
141
  print(f'pytest process running: {os.environ["PYTEST_CURRENT_TEST"]}')
142
142
  return True
@@ -204,12 +204,6 @@ class AppWindow(QMainWindow):
204
204
  self.ui.PropertiesTemplatesListWidget.setFont(mid_font)
205
205
  self.ui.depositOutputTextBrowser.setFont(mid_font)
206
206
 
207
- def format_report_button(self):
208
- if self.report_without_template():
209
- self.ui.SaveFullReportButton.setText('Make Report')
210
- else:
211
- self.ui.SaveFullReportButton.setText('Make Report from Template')
212
-
213
207
  def set_window_size_and_position(self) -> None:
214
208
  wsettings = self.settings.load_window_position()
215
209
  with suppress(TypeError):
@@ -312,7 +306,7 @@ class AppWindow(QMainWindow):
312
306
  self.ui.BackPushButton.clicked.connect(self.back_to_main)
313
307
  self.ui.BackFromDepositPushButton.clicked.connect(self.back_to_main)
314
308
  self.ui.ExploreDirButton.clicked.connect(self.explore_current_dir)
315
- self.ui.LoopsPushButton.clicked.connect(self.ui.MainStackedWidget.go_to_loops_page)
309
+ self.ui.LoopsPushButton.clicked.connect(self._on_go_to_loops_page)
316
310
  self.ui.LoopsPushButton.clicked.connect(
317
311
  lambda x: self.ui.LoopsTabWidget.setCurrentIndex(1) if self.ui.LoopsTabWidget.count() > 0 else None)
318
312
  self.ui.LoopsPushButton.clicked.connect(lambda x: self.ui.TemplatesStackedWidget.setCurrentIndex(1))
@@ -339,6 +333,7 @@ class AppWindow(QMainWindow):
339
333
  self.ui.CODpushButton.clicked.connect(self.open_cod_page)
340
334
  self.ui.CCDCpushButton.clicked.connect(self._ccdc_deposit)
341
335
  self.ui.newLoopPushButton.clicked.connect(self._go_to_new_loop_page)
336
+ self.ui.deleteLoopButton.clicked.connect(self._on_delete_current_loop)
342
337
  #
343
338
  save_shortcut = QShortcut(QtGui.QKeySequence('Ctrl+S'), self)
344
339
  save_shortcut.activated.connect(self.save_current_cif_file)
@@ -392,6 +387,10 @@ class AppWindow(QMainWindow):
392
387
  def finalcif_changes_filename(self):
393
388
  return self.cif.finalcif_file_prefixed(prefix='', suffix='-finalcif_changes.cif', force_strip=True)
394
389
 
390
+ def _on_go_to_loops_page(self):
391
+ self.make_loops_tables()
392
+ self.ui.MainStackedWidget.go_to_loops_page()
393
+
395
394
  def export_all_templates(self, filename: Path = None):
396
395
  import pickle
397
396
  if not filename:
@@ -606,7 +605,7 @@ class AppWindow(QMainWindow):
606
605
  self.save_current_cif_file()
607
606
  self.load_cif_file(self.cif.finalcif_file, self.current_block, load_changes=False)
608
607
  self.deposit.cif = self.cif
609
- self.ui.MainStackedWidget.setCurrentIndex(7)
608
+ self.ui.MainStackedWidget.got_to_cod_page()
610
609
 
611
610
  def event(self, event: QEvent) -> bool:
612
611
  if event.type() == QEvent.KeyPress:
@@ -625,7 +624,9 @@ class AppWindow(QMainWindow):
625
624
  if left_frame <= 300:
626
625
  left_frame = 300
627
626
  self.ui.LeftFrame.setMinimumWidth(int(left_frame))
628
- threading.Thread(target=self.ui.cif_main_table.resizeRowsToContents).start()
627
+ # Not necessary here, it is done in MyCifTable
628
+ # threading.Thread(target=self.ui.cif_main_table.resizeRowsToContents).start()
629
+ # QtCore.QTimer(self).singleShot(0, self.ui.cif_main_table.resizeRowsToContents)
629
630
 
630
631
  def moveEvent(self, a0: QtGui.QMoveEvent) -> None:
631
632
  """Is called when the main window moves."""
@@ -691,8 +692,8 @@ class AppWindow(QMainWindow):
691
692
  # parent must be None, otherwise it can't be moved to a thread:
692
693
  self.worker = MyDownloader(mainurl, parent=None)
693
694
  self.worker.loaded.connect(self.is_update_necessary)
694
- self.thread = threading.Thread(target=self.worker.download)
695
- self.thread.start()
695
+ self.thread_version = threading.Thread(target=self.worker.download)
696
+ self.thread_version.start()
696
697
 
697
698
  def is_update_necessary(self, content: bytes) -> None:
698
699
  """
@@ -761,8 +762,8 @@ class AppWindow(QMainWindow):
761
762
  url = 'http://www.platonsoft.nl/xraysoft/unix/platon/check.def'
762
763
  self.worker = MyDownloader(url, parent=None)
763
764
  self.worker.loaded.connect(self._save_checkdef)
764
- self.thread = threading.Thread(target=self.worker.download)
765
- self.thread.start()
765
+ self.thread_download = threading.Thread(target=self.worker.download)
766
+ self.thread_download.start()
766
767
 
767
768
  def _save_checkdef(self, reply: bytes) -> None:
768
769
  """
@@ -829,7 +830,6 @@ class AppWindow(QMainWindow):
829
830
  self.status_bar.show_message('')
830
831
  self.ui.TemplatesStackedWidget.setCurrentIndex(0)
831
832
  self.ui.MainStackedWidget.got_to_main_page()
832
- self.format_report_button()
833
833
  self.ui.revertLoopsPushButton.show()
834
834
  self.ui.newLoopPushButton.show()
835
835
 
@@ -859,9 +859,9 @@ class AppWindow(QMainWindow):
859
859
  self.ui.CheckCIFResultsTabWidget.setCurrentIndex(1) # Index 1 is html page
860
860
  self.checkcif_browser.load(url)
861
861
  self.ui.ResponsesTabWidget.setCurrentIndex(0)
862
+ threading.Thread(target=self._display_structure_factor_report, args=(parser,)).start()
862
863
  # The picture file linked in the html file:
863
- imageobj = self.cif.finalcif_file.with_suffix('.gif')
864
- gif = parser.get_image()
864
+ threading.Thread(target=parser.save_image, args=(self.cif.finalcif_file.with_suffix('.gif'),)).start()
865
865
  self.ui.CheckCifLogPlainTextEdit.appendPlainText('CheckCIF Report finished.')
866
866
  forms = parser.response_forms
867
867
  # makes all gray:
@@ -881,8 +881,9 @@ class AppWindow(QMainWindow):
881
881
  item = QListWidgetItem(' No level A, B or C alerts to explain.')
882
882
  self.ui.responseFormsListWidget.addItem(iteme)
883
883
  self.ui.responseFormsListWidget.addItem(item)
884
- if gif:
885
- imageobj.write_bytes(gif)
884
+
885
+ def _display_structure_factor_report(self, parser: MyHTMLParser) -> None:
886
+ self.ui.ckf_textedit.setPlainText(parser.get_ckf())
886
887
 
887
888
  def do_html_checkcif(self) -> None:
888
889
  """
@@ -1045,7 +1046,7 @@ class AppWindow(QMainWindow):
1045
1046
  font = doc.defaultFont()
1046
1047
  font.setFamily("Courier New")
1047
1048
  font.setStyleHint(QtGui.QFont.Monospace)
1048
- app.processEvents()
1049
+ # app.processEvents()
1049
1050
  font.setPointSize(14)
1050
1051
  doc.setDefaultFont(font)
1051
1052
 
@@ -1134,12 +1135,12 @@ class AppWindow(QMainWindow):
1134
1135
  raise
1135
1136
  print('Unable to open cif file')
1136
1137
  show_general_warning(self, 'The report document {} could not be opened.\n'
1137
- 'Is the file already opened?'.format(report_filename.name))
1138
+ 'Is the file already opened?'.format(report_filename.name))
1138
1139
  return
1139
1140
  if not self.running_inside_unit_test:
1140
1141
  self.open_report_document(report_filename, multi_table_document)
1141
- # Save report and other files to a zip file:
1142
- self.zip_report(report_filename)
1142
+ # Save report and other files to a zip file:
1143
+ self.zip_report(report_filename)
1143
1144
 
1144
1145
  def report_without_template(self) -> bool:
1145
1146
  """Check whether the report is generated from a template or hard-coded"""
@@ -1208,12 +1209,13 @@ class AppWindow(QMainWindow):
1208
1209
  if not self.cif:
1209
1210
  # No file is opened
1210
1211
  return None
1211
- self.cif.rename_data_name(''.join(self.ui.datanameComboBox.currentText().split(' ')))
1212
+ if not self.cif.is_multi_cif:
1213
+ self.cif.rename_data_name(''.join(self.ui.datanameComboBox.currentText().split(' ')))
1212
1214
  self.store_data_from_table_rows()
1213
1215
  self.save_ccdc_number()
1214
1216
  try:
1215
1217
  self.cif.save()
1216
- self.status_bar.show_message(' File Saved: {}'.format(self.cif.finalcif_file), 10)
1218
+ self.status_bar.show_message(f' File Saved: {self.cif.finalcif_file}', 10)
1217
1219
  print('File saved ...')
1218
1220
  return True
1219
1221
  except Exception as e:
@@ -1245,7 +1247,7 @@ class AppWindow(QMainWindow):
1245
1247
  if col_data and not col_edit and col_data != '?':
1246
1248
  self.cif[vhead] = col_data
1247
1249
  if col_edit:
1248
- if self.cif[vhead] != col_edit and changes_cif:
1250
+ if self.cif[vhead] != col_edit and changes_cif and vhead != '_audit_creation_method':
1249
1251
  changes_cif[vhead] = col_edit
1250
1252
  try:
1251
1253
  self.cif[vhead] = col_edit
@@ -1310,6 +1312,7 @@ class AppWindow(QMainWindow):
1310
1312
  if item.pair is not None:
1311
1313
  key, value = item.pair
1312
1314
  value = gemmi.cif.as_string(value).strip()
1315
+ self.add_row(key=key, value=value)
1313
1316
  self.ui.cif_main_table.setText(key=key, column=Column.EDIT, color=None, txt=value)
1314
1317
  for loop in changes.loops:
1315
1318
  self.cif.add_loop_to_cif(loop_tags=loop.tags, loop_values=loop.values)
@@ -1362,63 +1365,43 @@ class AppWindow(QMainWindow):
1362
1365
  except RuntimeError as e:
1363
1366
  show_general_warning(self, 'Could not import {}:\n'.format(filename) + str(e))
1364
1367
  return
1365
- except ValueError as e:
1368
+ except GemmiError as e:
1366
1369
  warning = 'Problems parsing file: {}:\n'.format(filename) + str(e)
1367
1370
  if 'data_' in str(e):
1368
1371
  warning = warning + "\n\nA CIF needs to start with 'data_[some_name]'."
1369
- show_general_warning(self, warning)
1372
+ show_general_warning(self, warning)
1373
+ return
1374
+ unable_to_open_message(self, Path(self.cif.filename), e)
1370
1375
  return
1371
1376
  except IOError as e:
1372
1377
  show_general_warning(self, 'Unable to open file {}:\n'.format(filename) + str(e))
1373
1378
  return
1374
1379
  self.check_cif_for_missing_values_before_really_open_it()
1375
- try:
1376
- self.import_key_value_pairs(imp_cif)
1377
- self.import_loops(imp_cif)
1378
- except Exception as e:
1379
- print(e)
1380
- unable_to_open_message(self, Path(self.cif.filename), e)
1381
- # I think I leave the user possibilities to change the imported values:
1382
- # self.save_current_cif_file()
1383
- # self.load_cif_file(str(self.cif.finalcif_file))
1380
+ self.import_selector = ImportSelector(self, import_cif=imp_cif, target_cif=self.cif, settings=self.settings)
1381
+ self.import_selector.show_import_window()
1382
+ self.import_selector.import_clicked.connect(self._do_import_cif_after_selection)
1383
+
1384
+ def _do_import_cif_after_selection(self, keys: List[str], loops: List[List[str]]) -> None:
1385
+ self._import_key_value_pairs(keys)
1386
+ self._import_loops(loops)
1387
+ self.add_audit_creation_method()
1388
+ self.import_selector.deleteLater()
1389
+ self.import_selector.close()
1390
+
1391
+ def _import_key_value_pairs(self, keys: List[str]) -> None:
1392
+ for key in keys:
1393
+ value = self.import_selector.import_cif[key]
1394
+ if key in self.ui.cif_main_table.vheaderitems:
1395
+ self.ui.cif_main_table.setText(key=key, column=Column.EDIT, txt=value, color=light_green)
1396
+ else:
1397
+ self.add_row(key, value, at_start=True)
1384
1398
 
1385
- def import_loops(self, imp_cif: 'CifContainer'):
1386
- """
1387
- Import all loops from the CifContainer imp_cif to the current block.
1388
- """
1389
- for loop in imp_cif.loops:
1390
- if self.ui.importOnlyNewDataCheckBox.isChecked() and self.cif.block.find(loop.tags):
1391
- # Import only new loops
1392
- continue
1393
- new_loop = self.cif.block.init_loop('', loop.tags)
1394
- for row in imp_cif.block.find(loop.tags):
1399
+ def _import_loops(self, loops: List[List[str]]):
1400
+ for loop in loops:
1401
+ new_loop = self.cif.block.init_loop('', loop)
1402
+ for row in self.import_selector.import_cif.block.find(loop):
1395
1403
  new_loop.add_row(row)
1396
1404
 
1397
- def import_key_value_pairs(self, imp_cif: CifContainer) -> None:
1398
- for item in imp_cif.block:
1399
- if item.pair is not None:
1400
- key, value = item.pair
1401
- # leave out unit cell etc.:
1402
- if self.do_not_import_this_key(key, value, imp_cif):
1403
- continue
1404
- if self.ui.importOnlyNewDataCheckBox.isChecked() and self.cif[key]:
1405
- # Import only new key/values
1406
- continue
1407
- value = cif.as_string(value)
1408
- if key in self.ui.cif_main_table.vheaderitems:
1409
- self.ui.cif_main_table.setText(key=key, column=Column.EDIT, txt=value, color=light_green)
1410
- else:
1411
- self.add_row(key, value) # , column =Column.EDIT
1412
-
1413
- def do_not_import_this_key(self, key: str, value: str, cif: 'CifContainer') -> bool:
1414
- if value == '?' or value.strip() == '':
1415
- return True
1416
- if key in do_not_import_keys:
1417
- return True
1418
- if key in do_not_import_from_stoe_cfx and cif.fileobj.suffix == '.cfx':
1419
- return True
1420
- return False
1421
-
1422
1405
  def load_cif_file(self, filepath: Path, block=0, load_changes: bool = True) -> None:
1423
1406
  """
1424
1407
  Opens the cif file and fills information into the main table.
@@ -1472,6 +1455,7 @@ class AppWindow(QMainWindow):
1472
1455
 
1473
1456
  def _clear_state_before_block_load(self) -> None:
1474
1457
  self.status_bar.show_message('')
1458
+ self.ui.ckf_textedit.clear()
1475
1459
  # Set to empty state before loading:
1476
1460
  self.missing_data = set()
1477
1461
  # clean table and vheader before loading:
@@ -1515,11 +1499,10 @@ class AppWindow(QMainWindow):
1515
1499
  if self.changes_answer == QMessageBox.Yes:
1516
1500
  try:
1517
1501
  self.load_changes_cif()
1518
- except Exception as e:
1502
+ except GemmiError as e:
1519
1503
  unable_to_open_message(parent=self, filepath=self.finalcif_changes_filename, not_ok=e)
1520
1504
  if self.running_inside_unit_test and changes_exist:
1521
1505
  self.load_changes_cif()
1522
- self.make_loops_tables()
1523
1506
  if self.cif:
1524
1507
  self.set_shredcif_state()
1525
1508
  # saving current cif dir as last working directory:
@@ -1531,7 +1514,7 @@ class AppWindow(QMainWindow):
1531
1514
  self.ui.CheckcifPlaintextEdit.clear()
1532
1515
  self.ui.TemplatesStackedWidget.setCurrentIndex(0)
1533
1516
  self.authors = AuthorLoops(ui=self.ui, cif=self.cif, app=self)
1534
- if not self.ui.MainStackedWidget.on_checkcif_page():
1517
+ if not (self.ui.MainStackedWidget.on_checkcif_page() or self.ui.MainStackedWidget.on_info_page()):
1535
1518
  self.ui.MainStackedWidget.got_to_main_page()
1536
1519
  self.deposit.cif = self.cif
1537
1520
  # self.ui.cif_main_table.resizeRowsToContents()
@@ -1539,6 +1522,9 @@ class AppWindow(QMainWindow):
1539
1522
  for row_number in range(self.ui.cif_main_table.model().rowCount()):
1540
1523
  vhead_key = self.get_key_by_row_number(row_number)
1541
1524
  self.ui.cif_main_table.vheaderitems.insert(row_number, vhead_key)
1525
+ if self.ui.MainStackedWidget.on_info_page():
1526
+ self.show_residuals()
1527
+ self.redraw_molecule()
1542
1528
 
1543
1529
  def changes_cif_has_values(self) -> bool:
1544
1530
  try:
@@ -1578,8 +1564,9 @@ class AppWindow(QMainWindow):
1578
1564
  if cif2.is_multi_cif:
1579
1565
  show_general_warning(self, 'Can add single data CIFs only!')
1580
1566
  if cif2.block.name in [x.name for x in self.cif.doc]:
1581
- show_general_warning(self, warn_text='Duplicate block', info_text='Data block name "<b>{}</b>" already present '
1582
- 'in current CIF!'.format(self.cif.block.name))
1567
+ show_general_warning(self, warn_text='Duplicate block',
1568
+ info_text=f'Data block name "<b>{self.cif.block.name}</b>" '
1569
+ f'already present in current CIF!')
1583
1570
  return
1584
1571
  self.cif.doc.add_copied_block(block=cif2.block, pos=-1)
1585
1572
  self.cif.save()
@@ -1604,10 +1591,10 @@ class AppWindow(QMainWindow):
1604
1591
  print(str(e))
1605
1592
  errlist = str(e).split(':')
1606
1593
  if len(errlist) > 1:
1607
- show_general_warning(self,
1608
- f"Attention in CIF line {errlist[1]}:\n'{errlist[2].split()[0]}' has no value.")
1594
+ show_general_warning(self, f"Attention in CIF line {errlist[1]}:\n"
1595
+ f"'{errlist[2].split()[0]}' has no value.")
1609
1596
 
1610
- def get_last_workdir(self):
1597
+ def get_last_workdir(self) -> str:
1611
1598
  try:
1612
1599
  # loading last working directory:
1613
1600
  last = self.settings.load_last_workdir()
@@ -1634,9 +1621,9 @@ class AppWindow(QMainWindow):
1634
1621
 
1635
1622
  def warn_about_bad_cif(self):
1636
1623
  show_general_warning(self, "You have non-ascii characters like umlauts in the SHELX file "
1637
- "attached to this CIF.\n\n"
1638
- "FinalCif tries to convert them, but be warned "
1639
- "(they are not allowed in CIF1 files anyway).\n")
1624
+ "attached to this CIF.\n\n"
1625
+ "FinalCif tries to convert them, but be warned "
1626
+ "(they are not allowed in CIF1 files anyway).\n")
1640
1627
 
1641
1628
  def show_residuals(self) -> None:
1642
1629
  """
@@ -1696,8 +1683,8 @@ class AppWindow(QMainWindow):
1696
1683
  if self.cif.res_file_data:
1697
1684
  self.ui.shelx_TextEdit.setPlainText(cif.as_string(self.cif.res_file_data))
1698
1685
  try:
1699
- #QtCore.QTimer(self).singleShot(0, self.view_molecule)
1700
- threading.Thread(target=self.view_molecule).start()
1686
+ QtCore.QTimer(self).singleShot(0, self.view_molecule)
1687
+ # threading.Thread(target=self.view_molecule).start()
1701
1688
  except Exception:
1702
1689
  print('Molecule view crashed!')
1703
1690
 
@@ -1842,10 +1829,8 @@ class AppWindow(QMainWindow):
1842
1829
  value = '?'
1843
1830
  self.add_row(key, value)
1844
1831
  if key == '_audit_creation_method':
1845
- txt = 'FinalCif V{} by Daniel Kratzert, Freiburg {}, https://dkratzert.de/finalcif.html'
1846
- strval = txt.format(VERSION, datetime.now().year)
1847
- self.ui.cif_main_table.setText(key=key, column=Column.DATA, txt=strval)
1848
- #threading.Thread(target=self.ui.cif_main_table.resizeRowsToContents).start()
1832
+ self.add_audit_creation_method(key)
1833
+ # QtCore.QTimer(self).singleShot(200, self.ui.cif_main_table.resizeRowsToContents)
1849
1834
  # print(key, value)
1850
1835
  if not self.cif.test_res_checksum():
1851
1836
  show_res_checksum_warning(parent=self)
@@ -1858,6 +1843,12 @@ class AppWindow(QMainWindow):
1858
1843
  self.erase_disabled_items()
1859
1844
  self.ui.cif_main_table.setCurrentItem(None)
1860
1845
 
1846
+ def add_audit_creation_method(self, key: str = '_audit_creation_method') -> None:
1847
+ txt = 'FinalCif V{} by Daniel Kratzert, Freiburg {}, https://dkratzert.de/finalcif.html'
1848
+ strval = txt.format(VERSION, datetime.now().year)
1849
+ self.ui.cif_main_table.setText(key=key, column=Column.DATA, txt=strval)
1850
+ self.ui.cif_main_table.setText(key=key, column=Column.EDIT, txt=strval)
1851
+
1861
1852
  def make_loops_tables(self) -> None:
1862
1853
  for _ in range(self.ui.LoopsTabWidget.count()):
1863
1854
  # I use this, so that always the first tab stays.
@@ -1869,13 +1860,13 @@ class AppWindow(QMainWindow):
1869
1860
  """
1870
1861
  Generates a list of tables containing the cif loops.
1871
1862
  """
1872
- do_not_display = ('_diffrn_refln_index_h')
1863
+ # do_not_display = ('_diffrn_refln_index_h')
1873
1864
  for num, loop in enumerate(self.cif.loops):
1874
1865
  tags = loop.tags
1875
1866
  if not tags or len(tags) < 1:
1876
1867
  continue
1877
- if tags[0] in do_not_display:
1878
- continue
1868
+ # if tags[0] in do_not_display:
1869
+ # continue
1879
1870
  self.new_loop_tab(loop, num, tags)
1880
1871
  if self.cif.res_file_data:
1881
1872
  self.add_res_file_to_loops()
@@ -1911,6 +1902,20 @@ class AppWindow(QMainWindow):
1911
1902
  self.ui.newLoopPushButton.hide()
1912
1903
  self.loopcreate.saveLoopPushButton.clicked.connect(self.save_new_loop_to_cif)
1913
1904
 
1905
+ def _on_delete_current_loop(self):
1906
+ current_tab_index = self.ui.LoopsTabWidget.currentIndex()
1907
+ current_table_view: MyQTableView = self.ui.LoopsTabWidget.widget(current_tab_index)
1908
+ try:
1909
+ header_model: LoopTableModel = current_table_view.horizontalHeader().model()
1910
+ except AttributeError:
1911
+ # Not a QTableView
1912
+ return
1913
+ header_item = header_model._header[0]
1914
+ loop: gemmi.cif.Loop = self.cif.block.find_loop(header_item).get_loop()
1915
+ table: gemmi.cif.Table = self.cif.block.find(loop.tags)
1916
+ table.erase()
1917
+ self.ui.LoopsTabWidget.removeTab(current_tab_index)
1918
+
1914
1919
  def save_new_loop_to_cif(self):
1915
1920
  if self.loopcreate:
1916
1921
  loop = self.loopcreate.save_new_loop_to_cif()
@@ -149,6 +149,7 @@ def fix_iucr_urls(content: str):
149
149
  class MyHTMLParser(HTMLParser):
150
150
  def __init__(self, data):
151
151
  self.pdf_link = ''
152
+ self.structure_factor_report = ''
152
153
  self.imageurl = ''
153
154
  super(MyHTMLParser, self).__init__()
154
155
  self.vrf = ''
@@ -159,10 +160,14 @@ class MyHTMLParser(HTMLParser):
159
160
  return requests.get(self.pdf_link, timeout=10).content
160
161
 
161
162
  def handle_starttag(self, tag: str, attrs: str) -> None:
162
- if tag == "a" and len(attrs) > 1 and attrs[0][1] == '_blank' and attrs[1][1].endswith('.pdf'):
163
- url = attrs[1][1]
164
- self.pdf_link = url
165
- if tag == "img" and len(attrs) > 1 and attrs[0][0] == 'width' and '.gif' in attrs[1][1]:
163
+ # if tag and tag not in ('font', 'div', 'link', 'meta', 'html', 'table', 'td') and attrs:
164
+ # # For debug:
165
+ # print(f'tag: {tag}, attrs: {attrs}')
166
+ if tag == "a" and len(attrs) > 1 and attrs[1][0] == 'href' and attrs[1][1].endswith('.pdf'):
167
+ self.pdf_link = attrs[1][1]
168
+ if tag == "a" and len(attrs) > 1 and attrs[0][0] == 'href' and attrs[0][1].endswith('ckf.html'):
169
+ self.structure_factor_report = attrs[0][1]
170
+ if tag == "img" and len(attrs) > 1 and attrs[0][0] == 'width' and attrs[1][1].endswith('.gif'):
166
171
  url = attrs[1][1]
167
172
  self.imageurl = url
168
173
 
@@ -172,11 +177,20 @@ class MyHTMLParser(HTMLParser):
172
177
  if data.startswith('PLAT') and len(data) == 17:
173
178
  self.alert_levels.append(data)
174
179
 
175
- def get_image(self) -> bytes:
180
+ def save_image(self, image_file: Path) -> None:
181
+ try:
182
+ image = requests.get(self.imageurl, timeout=10).content
183
+ except MissingSchema:
184
+ print('debug: Got no image from checkcif server.')
185
+ image = b''
186
+ if image:
187
+ image_file.write_bytes(image)
188
+
189
+ def get_ckf(self) -> str:
176
190
  try:
177
- return requests.get(self.imageurl, timeout=10).content
191
+ return requests.get(self.structure_factor_report, timeout=10).content.decode('latin1', 'ignore')
178
192
  except MissingSchema:
179
- return b''
193
+ return ''
180
194
 
181
195
  @property
182
196
  def response_forms(self) -> List[Dict[str, str]]:
@@ -244,18 +258,19 @@ class AlertHelp():
244
258
 
245
259
 
246
260
  if __name__ == "__main__":
247
- cif = Path('test-data/1000007-finalcif.cif')
248
- html = Path(r'tests/examples/work/checkcif-cu_BruecknerJK_153F40_0m-finalcif.html')
249
- # ckf = CheckCif(None, cif, outfile=html)
250
- # ckf.show_html_report()
251
- # sys.exit()
252
- # ckf.show_pdf_report()
253
- # html = Path(r'D:\frames\guest\BreitPZ_R_122\BreitPZ_R_122\checkcif-BreitPZ_R_122_0m_a.html')
261
+ html = Path(r'tests/checkcif_results/check_html_ab.html')
262
+ html_pdf = Path(r'tests/checkcif_results/check_pdf_ab.html')
254
263
  parser = MyHTMLParser(html.read_text())
255
- # print(parser.imageurl)
256
- from pprint import pprint
264
+ print('html report link:', parser.structure_factor_report)
265
+ print('pdf link:', parser.pdf_link)
266
+ print('image url:', parser.imageurl)
267
+ print('###')
268
+ parser = MyHTMLParser(html_pdf.read_text())
269
+ print('html report link:', parser.structure_factor_report)
270
+ print('pdf link:', parser.pdf_link)
271
+ print('image url:', parser.imageurl)
257
272
 
258
- pprint(parser.response_forms)
273
+ # pprint(parser.response_forms)
259
274
  # print(parser.alert_levels)
260
275
  # print(parser.vrf)
261
276
  # print(parser.pdf)
@@ -127,7 +127,10 @@ class CifContainer():
127
127
  def _on_load(self) -> None:
128
128
  # will not ok with non-ascii characters in the res file:
129
129
  self.chars_ok = True
130
- self.doc.check_for_duplicates()
130
+ try:
131
+ self.doc.check_for_duplicates()
132
+ except RuntimeError as e:
133
+ raise GemmiError(e)
131
134
  self.order = order
132
135
  self.dsr_used = DSRFind(self.res_file_data).dsr_used
133
136
  self.atomic_struct: gemmi.SmallStructure = gemmi.make_small_structure_from_block(self.block)
@@ -610,8 +613,7 @@ class CifContainer():
610
613
  Renames data_ tags to the newname. Also _vrf tags are renamed accordingly.
611
614
  http://journals.iucr.org/services/cif/checking/checkfaq.html
612
615
  """
613
- # Have to use ord(), because Python 3.6 has not str.isascii():
614
- newname = ''.join([i for i in newname if ord(i) < 127])
616
+ newname = ''.join([i for i in newname if i.isascii()])
615
617
  self.block.name = newname
616
618
  for item in self.block:
617
619
  if item.pair is not None:
@@ -874,11 +876,11 @@ class CifContainer():
874
876
  for item in self.block:
875
877
  if item.pair is not None:
876
878
  key, value = item.pair
877
- if key.startswith('_shelx'):
878
- # No-one should edit shelx values:
879
- continue
880
- if key == '_iucr_refine_instructions_details':
881
- continue
879
+ #if key.startswith('_shelx'):
880
+ # # No-one should edit shelx values:
881
+ # continue
882
+ #if key == '_iucr_refine_instructions_details':
883
+ # continue
882
884
  if self._is_centrokey(key):
883
885
  continue
884
886
  if not value or value == '?' or value == "'?'":
@@ -88,7 +88,7 @@ class MoleculeWidget(QtWidgets.QWidget):
88
88
  self.painter.setFont(font)
89
89
  try:
90
90
  self.draw()
91
- except ValueError as e:
91
+ except (ValueError, IndexError) as e:
92
92
  print(f'Draw structure crashed: {e}')
93
93
  self.painter.end()
94
94
 
@@ -12,8 +12,9 @@ from finalcif.cif.text import retranslate_delimiter, utf8_to_str
12
12
  from finalcif.equip_property.tools import read_document_from_cif_file
13
13
  from finalcif.gui.dialogs import cif_file_open_dialog, show_general_warning, cif_file_save_dialog
14
14
  from finalcif.gui.plaintextedit import PlainTextEditTemplate
15
- from finalcif.tools.misc import predefined_property_templates
16
15
  from finalcif.tools.settings import FinalCifSettings
16
+ from finalcif.tools import misc
17
+
17
18
 
18
19
  with suppress(ImportError):
19
20
  from finalcif.appwindow import AppWindow
@@ -146,7 +147,7 @@ class Properties(QtCore.QObject):
146
147
 
147
148
  def store_predefined_templates(self) -> None:
148
149
  property_list = self.settings.get_properties_list() or []
149
- for item in predefined_property_templates:
150
+ for item in misc.predefined_property_templates:
150
151
  if item['name'] not in property_list:
151
152
  self.settings.save_settings_list('property', item['name'], item['values'])
152
153
 
@@ -2,7 +2,7 @@ import re
2
2
  from enum import IntEnum
3
3
  from typing import List
4
4
 
5
- from PyQt5 import QtCore
5
+ from PyQt5 import QtCore, QtGui
6
6
  from PyQt5.QtCore import QEvent, QObject, Qt
7
7
  from PyQt5.QtGui import QColor, QKeySequence, QBrush
8
8
  from PyQt5.QtWidgets import QAbstractScrollArea, QTableWidget, \
@@ -200,7 +200,7 @@ class MyCifTable(QTableWidget, ItemTextMixin):
200
200
  textedit.templateRequested.connect(self.goto_template_page)
201
201
  textedit.new_key.connect(lambda x: self.new_key.emit(x))
202
202
  self.setCellWidget(row, column, textedit)
203
- textedit.setText(txt, color=color)
203
+ textedit.setText(txt, color=color, column=column)
204
204
  if (column == Column.CIF) or (column == Column.DATA):
205
205
  textedit.setUneditable()
206
206
  if color:
@@ -240,7 +240,7 @@ class MyCifTable(QTableWidget, ItemTextMixin):
240
240
  Copies the content of a field.
241
241
  """
242
242
  row = self.currentRow()
243
- print(row, self.vheaderitems[row], '#')
243
+ # print(row, self.vheaderitems[row], '#')
244
244
  clipboard = QApplication.clipboard()
245
245
  clipboard.setText(self.vheaderitems[row])
246
246
 
@@ -273,6 +273,10 @@ class MyCifTable(QTableWidget, ItemTextMixin):
273
273
  hheader.setAlternatingRowColors(True)
274
274
  self.verticalHeader().setAlternatingRowColors(True)
275
275
 
276
+ def resizeEvent(self, e: QtGui.QResizeEvent) -> None:
277
+ QtCore.QTimer(self).singleShot(0, self.resizeRowsToContents)
278
+ super().resizeEvent(e)
279
+
276
280
 
277
281
  class MyTableWidgetItem(QTableWidgetItem):
278
282
 
@@ -108,7 +108,6 @@ def show_keyword_help(parent, helptext: str, title: str = ''):
108
108
  """
109
109
  nlines = len(helptext.splitlines())
110
110
  window = QMainWindow(parent=parent)
111
- window.setWindowFlags(Qt.Tool)
112
111
  window.setWindowTitle(title)
113
112
 
114
113
  def close_window(event):