tomwer 1.2.9__py3-none-any.whl → 1.3.0a0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. orangecontrib/tomwer/tutorials/icat_publication.ows +58 -0
  2. orangecontrib/tomwer/widgets/__init__.py +1 -0
  3. orangecontrib/tomwer/widgets/control/DataDiscoveryOW.py +2 -2
  4. orangecontrib/tomwer/widgets/control/DataListOW.py +9 -7
  5. orangecontrib/tomwer/widgets/control/DataSelectorOW.py +21 -10
  6. orangecontrib/tomwer/widgets/control/EDF2NXTomomillOW.py +11 -5
  7. orangecontrib/tomwer/widgets/control/EmailOW.py +4 -4
  8. orangecontrib/tomwer/widgets/control/NXTomomillOW.py +31 -18
  9. orangecontrib/tomwer/widgets/control/NXtomoConcatenate.py +14 -7
  10. orangecontrib/tomwer/widgets/control/NotifierOW.py +1 -0
  11. orangecontrib/tomwer/widgets/control/VolumeSelector.py +7 -4
  12. orangecontrib/tomwer/widgets/control/VolumeSymLinkOW.py +182 -182
  13. orangecontrib/tomwer/widgets/debugtools/DatasetGeneratorOW.py +4 -4
  14. orangecontrib/tomwer/widgets/edit/DarkFlatPatchOW.py +4 -4
  15. orangecontrib/tomwer/widgets/edit/ImageKeyEditorOW.py +3 -3
  16. orangecontrib/tomwer/widgets/edit/ImageKeyUpgraderOW.py +2 -0
  17. orangecontrib/tomwer/widgets/edit/NXtomoEditorOW.py +3 -3
  18. orangecontrib/tomwer/widgets/edit/test/test_nxtomo_editor.py +3 -3
  19. orangecontrib/tomwer/widgets/icat/PublishProcessedDataOW.py +115 -0
  20. orangecontrib/tomwer/widgets/icat/RawDataScreenshotCreatorOW.py +98 -0
  21. orangecontrib/tomwer/widgets/icat/SaveToGalleryAndPublishOW.py +129 -0
  22. orangecontrib/tomwer/widgets/icat/__init__.py +13 -0
  23. orangecontrib/tomwer/widgets/icat/icons/add_gallery.png +0 -0
  24. orangecontrib/tomwer/widgets/icat/icons/add_gallery.svg +82 -0
  25. orangecontrib/tomwer/widgets/icat/icons/publish_processed_data.png +0 -0
  26. orangecontrib/tomwer/widgets/icat/icons/publish_processed_data.svg +95 -0
  27. orangecontrib/tomwer/widgets/icat/icons/raw_screenshots.png +0 -0
  28. orangecontrib/tomwer/widgets/icat/icons/raw_screenshots.svg +143 -0
  29. orangecontrib/tomwer/widgets/icons/tomwer_data_portal.png +0 -0
  30. orangecontrib/tomwer/widgets/icons/tomwer_data_portal.svg +76 -0
  31. orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +9 -8
  32. orangecontrib/tomwer/widgets/reconstruction/CastNabuVolumeOW.py +3 -3
  33. orangecontrib/tomwer/widgets/reconstruction/NabuHelicalPrepareWeightsDoubleOW.py +179 -169
  34. orangecontrib/tomwer/widgets/reconstruction/NabuOW.py +23 -0
  35. orangecontrib/tomwer/widgets/reconstruction/NabuVolumeOW.py +39 -5
  36. orangecontrib/tomwer/widgets/reconstruction/SAAxisOW.py +7 -13
  37. orangecontrib/tomwer/widgets/reconstruction/SADeltaBetaOW.py +7 -17
  38. orangecontrib/tomwer/widgets/reconstruction/SinoNormOW.py +3 -4
  39. orangecontrib/tomwer/widgets/visualization/LivesliceOW.py +1 -1
  40. orangecontrib/tomwer/widgets/visualization/NXtomoMetadataViewerOW.py +3 -3
  41. orangecontrib/tomwer/widgets/visualization/VolumeViewerOW.py +3 -29
  42. tomwer/__main__.py +11 -58
  43. tomwer/app/canvas.py +8 -0
  44. tomwer/app/canvas_launcher/config.py +13 -11
  45. tomwer/app/darkref.py +1 -1
  46. tomwer/app/darkrefpatch.py +1 -1
  47. tomwer/app/imagekeyeditor.py +5 -5
  48. tomwer/app/imagekeyupgrader.py +5 -5
  49. tomwer/app/intensitynormalization.py +2 -2
  50. tomwer/app/radiostack.py +2 -2
  51. tomwer/app/zstitching.py +74 -3
  52. tomwer/core/cluster/cluster.py +26 -0
  53. tomwer/core/log/logger.py +7 -5
  54. tomwer/core/process/conditions/filters.py +1 -1
  55. tomwer/core/process/control/datalistener/datalistener.py +3 -3
  56. tomwer/core/process/control/nxtomoconcatenate.py +13 -13
  57. tomwer/core/process/control/nxtomomill.py +83 -25
  58. tomwer/core/process/control/scantransfer.py +11 -10
  59. tomwer/core/process/control/scanvalidator.py +3 -2
  60. tomwer/core/process/control/test/test_concatenate_nxtomos.py +9 -9
  61. tomwer/core/process/control/test/test_email.py +4 -4
  62. tomwer/core/process/control/test/test_h52nx_process.py +59 -7
  63. tomwer/core/process/control/test/test_volume_link.py +64 -64
  64. tomwer/core/process/control/timer.py +1 -1
  65. tomwer/core/process/control/volumesymlink.py +200 -200
  66. tomwer/core/process/edit/darkflatpatch.py +6 -6
  67. tomwer/core/process/edit/imagekeyeditor.py +17 -18
  68. tomwer/core/process/icat/__init__.py +0 -0
  69. tomwer/core/process/icat/createscreenshots.py +100 -0
  70. tomwer/core/process/icat/gallery.py +377 -0
  71. tomwer/core/process/icat/icatbase.py +36 -0
  72. tomwer/core/process/icat/publish.py +228 -0
  73. tomwer/core/process/icat/screenshots.py +26 -0
  74. tomwer/core/process/output.py +52 -0
  75. tomwer/core/process/reconstruction/axis/axis.py +17 -10
  76. tomwer/core/process/reconstruction/axis/mode.py +4 -0
  77. tomwer/core/process/reconstruction/axis/params.py +9 -4
  78. tomwer/core/process/reconstruction/darkref/darkrefs.py +8 -6
  79. tomwer/core/process/reconstruction/darkref/darkrefscopy.py +1 -1
  80. tomwer/core/process/reconstruction/darkref/params.py +1 -1
  81. tomwer/core/process/reconstruction/lamino/tofu.py +4 -4
  82. tomwer/core/process/reconstruction/nabu/castvolume.py +1 -1
  83. tomwer/core/process/reconstruction/nabu/helical.py +9 -5
  84. tomwer/core/process/reconstruction/nabu/nabucommon.py +32 -62
  85. tomwer/core/process/reconstruction/nabu/nabuscores.py +387 -61
  86. tomwer/core/process/reconstruction/nabu/nabuslices.py +33 -21
  87. tomwer/core/process/reconstruction/nabu/nabuvolume.py +37 -14
  88. tomwer/core/process/reconstruction/nabu/settings.py +2 -2
  89. tomwer/core/process/reconstruction/nabu/utils.py +129 -24
  90. tomwer/core/process/reconstruction/output.py +108 -0
  91. tomwer/core/process/reconstruction/saaxis/saaxis.py +233 -263
  92. tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +140 -86
  93. tomwer/core/process/reconstruction/scores/params.py +4 -1
  94. tomwer/core/process/reconstruction/scores/scores.py +13 -0
  95. tomwer/core/process/reconstruction/test/test_axis_params.py +2 -2
  96. tomwer/core/process/reconstruction/test/test_darkref.py +3 -3
  97. tomwer/core/process/reconstruction/test/test_darkref_copy.py +3 -3
  98. tomwer/core/process/reconstruction/test/test_saaxis.py +3 -4
  99. tomwer/core/process/reconstruction/test/test_sadeltabeta.py +2 -2
  100. tomwer/core/process/stitching/nabustitcher.py +2 -2
  101. tomwer/core/process/test/test_axis.py +6 -6
  102. tomwer/core/process/test/test_dark_and_flat.py +10 -7
  103. tomwer/core/process/test/test_data_transfer.py +7 -6
  104. tomwer/core/process/test/test_nabu.py +4 -4
  105. tomwer/core/process/test/test_normalization.py +2 -2
  106. tomwer/core/scan/edfscan.py +4 -1
  107. tomwer/core/scan/hdf5scan.py +19 -500
  108. tomwer/core/scan/nxtomoscan.py +532 -0
  109. tomwer/core/scan/scanbase.py +42 -20
  110. tomwer/core/scan/scanfactory.py +13 -13
  111. tomwer/core/scan/test/test_future_scan.py +2 -2
  112. tomwer/core/scan/test/test_h5.py +12 -10
  113. tomwer/core/scan/test/test_process_registration.py +2 -2
  114. tomwer/core/scan/test/test_scan.py +4 -3
  115. tomwer/core/settings.py +20 -0
  116. tomwer/core/test/test_scanutils.py +8 -7
  117. tomwer/core/test/test_utils.py +33 -26
  118. tomwer/core/utils/__init__.py +0 -466
  119. tomwer/core/utils/deprecation.py +1 -1
  120. tomwer/core/utils/dictutils.py +14 -0
  121. tomwer/core/utils/lbsram.py +35 -0
  122. tomwer/core/utils/nxtomoutils.py +1 -1
  123. tomwer/core/utils/scanutils.py +6 -6
  124. tomwer/core/utils/spec.py +263 -0
  125. tomwer/core/volume/volumefactory.py +2 -2
  126. tomwer/gui/cluster/slurm.py +260 -60
  127. tomwer/gui/cluster/test/test_cluster.py +13 -0
  128. tomwer/gui/cluster/test/test_supervisor.py +2 -2
  129. tomwer/gui/configuration/__init__.py +0 -0
  130. tomwer/gui/{reconstruction/nabu → configuration}/action.py +1 -32
  131. tomwer/gui/configuration/level.py +22 -0
  132. tomwer/gui/control/actions.py +54 -0
  133. tomwer/gui/control/datalist.py +78 -16
  134. tomwer/gui/control/datalistener.py +4 -16
  135. tomwer/gui/control/{email.py → emailnotifier.py} +9 -18
  136. tomwer/gui/control/history.py +2 -2
  137. tomwer/gui/control/observations.py +2 -2
  138. tomwer/gui/control/reducedarkflatselector.py +1 -1
  139. tomwer/gui/control/selectorwidgetbase.py +36 -9
  140. tomwer/gui/control/serie/seriecreator.py +5 -22
  141. tomwer/gui/control/test/test_email.py +1 -1
  142. tomwer/gui/control/test/test_scanvalidator.py +6 -5
  143. tomwer/gui/control/test/test_single_tomo_obj.py +2 -2
  144. tomwer/gui/control/tomoobjdisplaymode.py +8 -0
  145. tomwer/gui/debugtools/datasetgenerator.py +3 -3
  146. tomwer/gui/edit/dkrfpatch.py +16 -22
  147. tomwer/gui/edit/imagekeyeditor.py +8 -11
  148. tomwer/gui/edit/nxtomoeditor.py +111 -44
  149. tomwer/gui/edit/nxtomowarmer.py +4 -4
  150. tomwer/gui/edit/test/test_dkrf_patch.py +7 -7
  151. tomwer/gui/edit/test/test_image_key_editor.py +3 -3
  152. tomwer/gui/edit/test/test_nx_editor.py +40 -16
  153. tomwer/gui/icat/__init__.py +0 -0
  154. tomwer/gui/icat/createscreenshots.py +80 -0
  155. tomwer/gui/icat/gallery.py +214 -0
  156. tomwer/gui/icat/publish.py +187 -0
  157. tomwer/gui/reconstruction/axis/axis.py +171 -57
  158. tomwer/gui/reconstruction/axis/radioaxis.py +80 -95
  159. tomwer/gui/reconstruction/darkref/darkrefcopywidget.py +3 -2
  160. tomwer/gui/reconstruction/lamino/tofu/projections.py +1 -1
  161. tomwer/gui/reconstruction/lamino/tofu/tofuoutput.py +3 -6
  162. tomwer/gui/reconstruction/nabu/castvolume.py +1 -1
  163. tomwer/gui/reconstruction/nabu/check.py +9 -9
  164. tomwer/gui/reconstruction/nabu/helical.py +29 -12
  165. tomwer/gui/reconstruction/nabu/nabuconfig/base.py +2 -4
  166. tomwer/gui/reconstruction/nabu/nabuconfig/output.py +110 -33
  167. tomwer/gui/reconstruction/nabu/nabuconfig/phase.py +9 -12
  168. tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +219 -29
  169. tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +3 -6
  170. tomwer/gui/reconstruction/nabu/nabuflow.py +12 -20
  171. tomwer/gui/reconstruction/nabu/slices.py +6 -7
  172. tomwer/gui/reconstruction/nabu/volume.py +22 -10
  173. tomwer/gui/reconstruction/normalization/intensity.py +15 -23
  174. tomwer/gui/reconstruction/saaxis/corrangeselector.py +7 -23
  175. tomwer/gui/reconstruction/saaxis/dimensionwidget.py +1 -1
  176. tomwer/gui/reconstruction/saaxis/saaxis.py +7 -9
  177. tomwer/gui/reconstruction/sadeltabeta/saadeltabeta.py +2 -1
  178. tomwer/gui/reconstruction/scores/control.py +2 -9
  179. tomwer/gui/reconstruction/scores/scoreplot.py +11 -5
  180. tomwer/gui/reconstruction/test/test_axis.py +23 -12
  181. tomwer/gui/reconstruction/test/test_lamino.py +8 -3
  182. tomwer/gui/reconstruction/test/test_nabu.py +28 -9
  183. tomwer/gui/reconstruction/test/test_saaxis.py +3 -3
  184. tomwer/gui/reconstruction/test/test_sadeltabeta.py +2 -2
  185. tomwer/gui/settings.py +5 -28
  186. tomwer/gui/stackplot.py +2 -5
  187. tomwer/gui/stitching/action.py +49 -0
  188. tomwer/gui/stitching/config/axisparams.py +7 -24
  189. tomwer/gui/stitching/config/output.py +10 -8
  190. tomwer/gui/stitching/config/positionoveraxis.py +22 -23
  191. tomwer/gui/stitching/normalization.py +117 -0
  192. tomwer/gui/stitching/stitchandbackground.py +4 -6
  193. tomwer/gui/stitching/stitching.py +265 -43
  194. tomwer/gui/stitching/stitching_preview.py +62 -5
  195. tomwer/gui/stitching/stitching_raw.py +2 -5
  196. tomwer/gui/stitching/z_stitching/fineestimation.py +0 -60
  197. tomwer/gui/utils/buttons.py +112 -29
  198. tomwer/gui/utils/inputwidget.py +33 -25
  199. tomwer/gui/utils/scandescription.py +4 -0
  200. tomwer/gui/utils/step.py +144 -0
  201. tomwer/gui/utils/unitsystem.py +2 -5
  202. tomwer/gui/utils/vignettes.py +176 -15
  203. tomwer/gui/visualization/dataviewer.py +1 -4
  204. tomwer/gui/visualization/diffviewer/diffviewer.py +7 -16
  205. tomwer/gui/visualization/diffviewer/shiftwidget.py +2 -5
  206. tomwer/gui/visualization/scanoverview.py +1 -1
  207. tomwer/gui/visualization/sinogramviewer.py +1 -10
  208. tomwer/gui/visualization/test/test_diffviewer.py +3 -3
  209. tomwer/gui/visualization/test/test_nx_tomo_metadata_viewer.py +4 -4
  210. tomwer/gui/visualization/test/test_sinogramviewer.py +2 -2
  211. tomwer/gui/visualization/test/test_stacks.py +3 -3
  212. tomwer/gui/visualization/test/test_volumeviewer.py +2 -2
  213. tomwer/io/utils/raw_and_processed_data.py +84 -0
  214. tomwer/io/utils/tomoobj.py +4 -6
  215. tomwer/resources/gui/icons/ruler.png +0 -0
  216. tomwer/resources/gui/icons/ruler.svg +273 -0
  217. tomwer/resources/gui/icons/short_description.png +0 -0
  218. tomwer/resources/gui/icons/short_description.svg +58 -0
  219. tomwer/resources/gui/icons/url.png +0 -0
  220. tomwer/resources/gui/icons/url.svg +58 -0
  221. tomwer/synctools/stacks/edit/darkflatpatch.py +2 -2
  222. tomwer/synctools/stacks/edit/imagekeyeditor.py +2 -2
  223. tomwer/synctools/stacks/reconstruction/axis.py +4 -4
  224. tomwer/synctools/stacks/reconstruction/castvolume.py +2 -2
  225. tomwer/synctools/stacks/reconstruction/dkrefcopy.py +4 -10
  226. tomwer/synctools/stacks/reconstruction/nabu.py +2 -2
  227. tomwer/synctools/stacks/reconstruction/normalization.py +2 -2
  228. tomwer/synctools/stacks/reconstruction/saaxis.py +2 -2
  229. tomwer/synctools/stacks/reconstruction/sadeltabeta.py +2 -2
  230. tomwer/synctools/test/test_darkRefs.py +7 -58
  231. tomwer/synctools/test/test_foldertransfer.py +6 -6
  232. tomwer/synctools/utils/scanstages.py +6 -6
  233. tomwer/tests/conftest.py +34 -0
  234. tomwer/tests/datasets.py +13 -0
  235. tomwer/tests/test_scripts.py +92 -39
  236. tomwer/tests/utils.py +5 -0
  237. tomwer/version.py +3 -3
  238. {tomwer-1.2.9.dist-info → tomwer-1.3.0a0.dist-info}/METADATA +39 -39
  239. {tomwer-1.2.9.dist-info → tomwer-1.3.0a0.dist-info}/RECORD +248 -209
  240. tomwer/resources/gui/icons/esrf_1.svg +0 -307
  241. tomwer/resources/gui/icons/triangle.svg +0 -80
  242. tomwer/synctools/test/test_scanstages.py +0 -162
  243. tomwer/tests/utils/__init__.py +0 -247
  244. tomwer/tests/utils/utilstest.py +0 -220
  245. /tomwer/app/{saaxis.py → multicor.py} +0 -0
  246. /tomwer/app/{sadeltabeta.py → multipag.py} +0 -0
  247. /tomwer/core/process/control/{email.py → emailnotifier.py} +0 -0
  248. /tomwer-1.2.9-py3.11-nspkg.pth → /tomwer-1.3.0a0-py3.11-nspkg.pth +0 -0
  249. {tomwer-1.2.9.dist-info → tomwer-1.3.0a0.dist-info}/LICENSE +0 -0
  250. {tomwer-1.2.9.dist-info → tomwer-1.3.0a0.dist-info}/WHEEL +0 -0
  251. {tomwer-1.2.9.dist-info → tomwer-1.3.0a0.dist-info}/entry_points.txt +0 -0
  252. {tomwer-1.2.9.dist-info → tomwer-1.3.0a0.dist-info}/namespace_packages.txt +0 -0
  253. {tomwer-1.2.9.dist-info → tomwer-1.3.0a0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,80 @@
1
+ from silx.gui import qt
2
+ from typing import Optional
3
+
4
+
5
+ class CreateRawDataScreenshotsWidget(qt.QWidget):
6
+ """
7
+ Widget to allow the user define the screenshot to make of the raw data
8
+ """
9
+
10
+ sigConfigChanged = qt.Signal()
11
+ """emit when the configuration change"""
12
+
13
+ def __init__(self, parent=None):
14
+ super().__init__(parent)
15
+ self.setLayout(qt.QFormLayout())
16
+ # projections
17
+ self._projectionsCB = qt.QCheckBox("raw projections each", self)
18
+ self._projectionsSB = qt.QSpinBox(parent)
19
+ self._projectionsSB.setSuffix("°")
20
+ self.layout().addRow(self._projectionsCB, self._projectionsSB)
21
+ # flat field
22
+ self._flatFieldCB = qt.QCheckBox("first raw flat")
23
+ self.layout().addRow(self._flatFieldCB)
24
+ # dark field
25
+ self._darkFieldCB = qt.QCheckBox("first raw dark")
26
+ self.layout().addRow(self._darkFieldCB)
27
+
28
+ # set up
29
+ self._projectionsCB.setChecked(True)
30
+ self._flatFieldCB.setChecked(True)
31
+ self._darkFieldCB.setChecked(True)
32
+
33
+ # connect signal / slot
34
+ self._projectionsCB.toggled.connect(self._changed)
35
+ self._projectionsSB.valueChanged.connect(self._changed)
36
+ self._projectionsSB.setRange(0, 360)
37
+ self._projectionsSB.setValue(90)
38
+ self._flatFieldCB.toggled.connect(self._changed)
39
+ self._darkFieldCB.toggled.connect(self._changed)
40
+
41
+ def _changed(self, *args, **kwargs):
42
+ self.sigConfigChanged.emit()
43
+
44
+ def getConfiguration(self) -> dict:
45
+ return {
46
+ "raw_projections_required": self._projectionsCB.isChecked(),
47
+ "raw_projections_each": self._projectionsSB.value(),
48
+ "raw_darks_required": self._darkFieldCB.isChecked(),
49
+ "raw_flats_required": self._flatFieldCB.isChecked(),
50
+ }
51
+
52
+ def setRawProjections(self, required: bool, each_proj: Optional[int]):
53
+ self._projectionsCB.setChecked(required)
54
+ if each_proj is not None:
55
+ self._projectionsSB.setValue(int(each_proj))
56
+
57
+ def setFlatFieldRequired(self, required: bool):
58
+ self._flatFieldCB.setChecked(required)
59
+
60
+ def setDarkFieldRequired(self, required: bool):
61
+ self._darkFieldCB.setChecked(required)
62
+
63
+ def setConfiguration(self, configuration: dict):
64
+ assert isinstance(configuration, dict)
65
+ # handle raw projections
66
+ raw_projections_required = configuration.get(
67
+ "raw_projections_required", self._projectionsCB.isChecked()
68
+ )
69
+ raw_projections_each = configuration.get("raw_projections_each", None)
70
+ self.setRawProjections(
71
+ required=raw_projections_required, each_proj=raw_projections_each
72
+ )
73
+ # handle flat field
74
+ flat_field_required = configuration.get("raw_flats_required", None)
75
+ if flat_field_required is not None:
76
+ self.setFlatFieldRequired(flat_field_required)
77
+ # handle flat field
78
+ dark_field_required = configuration.get("raw_darks_required", None)
79
+ if dark_field_required is not None:
80
+ self.setDarkFieldRequired(dark_field_required)
@@ -0,0 +1,214 @@
1
+ import os
2
+ from silx.gui import qt
3
+ from silx.utils.enum import Enum as _Enum
4
+ from tomwer.core.process.icat.gallery import OutputFormat
5
+ from tomwer.gui.qlefilesystem import QLFileSystem
6
+ from tomwer.io.utils import get_default_directory
7
+ from tomwer.core.utils.dictutils import concatenate_dict
8
+ from tomwer.core.process.icat.gallery import Binning
9
+
10
+ from .publish import PublishProcessedDataWidget
11
+
12
+
13
+ class _GalleryOutputDir(qt.QGroupBox):
14
+ class OutputDirMode(_Enum):
15
+ DATASET_GALLERY = "dataset gallery"
16
+ PROPOSAL_GALLERY = "proposal GALLERY"
17
+ CUSTOM = "custom"
18
+
19
+ def __init__(self, parent=None):
20
+ super().__init__(parent)
21
+ self.setLayout(qt.QGridLayout())
22
+ # dataset gallery option
23
+ self._datasetGalleryQRB = qt.QRadioButton(
24
+ self.OutputDirMode.DATASET_GALLERY.value, self
25
+ )
26
+ self.layout().addWidget(self._datasetGalleryQRB, 0, 0, 1, 4)
27
+ # proposal gallery option
28
+ self._proposalGalleryQRB = qt.QRadioButton(
29
+ self.OutputDirMode.PROPOSAL_GALLERY.value, self
30
+ )
31
+ self.layout().addWidget(self._proposalGalleryQRB, 1, 0, 1, 4)
32
+
33
+ # other option
34
+ self._otherQRB = qt.QRadioButton(self.OutputDirMode.CUSTOM.value, self)
35
+ self._otherQRB.setCheckable(True)
36
+ self.layout().addWidget(self._otherQRB, 2, 0, 1, 4)
37
+
38
+ self._otherQLE = QLFileSystem(
39
+ "", self, filters=qt.QDir.NoDotAndDotDot | qt.QDir.Dirs
40
+ )
41
+ self.layout().addWidget(self._otherQLE, 3, 1, 1, 2)
42
+ style = qt.QApplication.style()
43
+ icon_opendir = style.standardIcon(qt.QStyle.SP_DirOpenIcon)
44
+ self._selectOtherQLE = qt.QPushButton(icon_opendir, "", self)
45
+ self._selectOtherQLE.setIcon(icon_opendir)
46
+ self.layout().addWidget(self._selectOtherQLE, 3, 3, 1, 1)
47
+
48
+ # button group
49
+ self._buttonGroup = qt.QButtonGroup()
50
+ self._buttonGroup.setExclusive(True)
51
+ self._buttonGroup.addButton(self._datasetGalleryQRB)
52
+ self._buttonGroup.addButton(self._proposalGalleryQRB)
53
+ self._buttonGroup.addButton(self._otherQRB)
54
+
55
+ # vertical spacer
56
+ self._vSpacer = qt.QWidget(self)
57
+ self._vSpacer.setSizePolicy(qt.QSizePolicy.Minimum, qt.QSizePolicy.Expanding)
58
+ self.layout().addWidget(self._vSpacer, 99, 0, 1, 1)
59
+
60
+ # set up GUI
61
+ self._datasetGalleryQRB.setChecked(True)
62
+ self._modeChanged()
63
+
64
+ # connect signal / slot
65
+ self._buttonGroup.buttonClicked.connect(self._modeChanged)
66
+ self._selectOtherQLE.released.connect(self._selectOutput)
67
+
68
+ def _selectOutput(self): # pragma: no cover
69
+ defaultDirectory = self._selectOtherQLE.text()
70
+ if not os.path.isdir(defaultDirectory):
71
+ defaultDirectory = get_default_directory()
72
+
73
+ dialog = qt.QFileDialog(self, directory=defaultDirectory)
74
+ dialog.setFileMode(qt.QFileDialog.DirectoryOnly)
75
+
76
+ if not dialog.exec_():
77
+ dialog.close()
78
+ return
79
+
80
+ self._selectOtherQLE.setText(dialog.selectedFiles()[0])
81
+
82
+ def getOutputFolderMode(self):
83
+ if self._datasetGalleryQRB.isChecked():
84
+ return _GalleryOutputDir.OutputDirMode.DATASET_GALLERY
85
+ elif self._proposalGalleryQRB.isChecked():
86
+ return _GalleryOutputDir.OutputDirMode.PROPOSAL_GALLERY
87
+ elif self._otherQRB.isChecked():
88
+ return _GalleryOutputDir.OutputDirMode.CUSTOM
89
+ else:
90
+ raise NotImplementedError
91
+
92
+ def setOutputFolderMode(self, mode):
93
+ mode = _GalleryOutputDir.OutputDirMode.from_value(mode)
94
+ if mode is _GalleryOutputDir.OutputDirMode.PROPOSAL_GALLERY:
95
+ self._proposalGalleryQRB.setChecked(True)
96
+ elif mode is _GalleryOutputDir.OutputDirMode.DATASET_GALLERY:
97
+ self._datasetGalleryQRB.setChecked(True)
98
+ elif mode is _GalleryOutputDir.OutputDirMode.CUSTOM:
99
+ self._otherQRB.setChecked(True)
100
+ else:
101
+ raise NotImplementedError
102
+ self._modeChanged()
103
+
104
+ def getOtherOutputDir(self):
105
+ return self._otherQLE.text()
106
+
107
+ def setOtherOutputDir(self, path: str):
108
+ self._otherQLE.setText(path)
109
+
110
+ def _modeChanged(self, *args, **kwargs):
111
+ custom_active = self._otherQRB.isChecked()
112
+ self._otherQLE.setEnabled(custom_active)
113
+ self._selectOtherQLE.setEnabled(custom_active)
114
+
115
+
116
+ class GalleryWidget(qt.QWidget):
117
+ """Widget to let the user define the output location of the screenshots"""
118
+
119
+ sigConfigChanged = qt.Signal()
120
+ """emit when the configuration has changed"""
121
+
122
+ def __init__(self, parent=None):
123
+ super().__init__(parent)
124
+ self.setLayout(qt.QFormLayout())
125
+
126
+ # screenshot precision
127
+ self._precisonQCB = qt.QComboBox(self)
128
+ self._precisonQCB.addItem("uint8")
129
+ self.layout().addRow("precision", self._precisonQCB)
130
+ # binning
131
+ self._binningQCB = qt.QComboBox(self)
132
+ self._binningQCB.addItems(Binning.values())
133
+ self.layout().addRow("binning", self._binningQCB)
134
+ self._binningQCB.setCurrentText(Binning.SIXTEEN_BY_SIXTEEN.value)
135
+ self._binningQCB.setToolTip(
136
+ "To speed up display of the gallery at the data portal side it is highly recommended to bin screenshots"
137
+ ) # recommanded size: 5ko for the entire gallery
138
+ # output format
139
+ self._outputFormat = qt.QComboBox(self)
140
+ self._outputFormat.addItems(OutputFormat.values())
141
+ self.layout().addRow("outoutput_location_modeput format", self._outputFormat)
142
+ # gallery output dir
143
+ self._outputDirWidget = _GalleryOutputDir(self)
144
+ self._outputLocationLabel = qt.QLabel("output location", self)
145
+ self.layout().addRow(self._outputLocationLabel, self._outputDirWidget)
146
+ self._outputDirWidget.hide()
147
+ self._outputLocationLabel.hide()
148
+ # overwrite
149
+ self._overwriteCB = qt.QCheckBox("overwrite", self)
150
+ self._overwriteCB.setChecked(True)
151
+ self.layout().addRow(self._overwriteCB)
152
+ # publishing setting
153
+ self._publishConfig = PublishProcessedDataWidget(self)
154
+ self._publisherGB = qt.QGroupBox("icat info")
155
+ self._publisherGB.setLayout(qt.QVBoxLayout())
156
+ self._publisherGB.layout().addWidget(self._publishConfig)
157
+ self.layout().addRow(self._publisherGB)
158
+ # connect signal / slot
159
+ self._outputFormat.currentIndexChanged.connect(self._configChanged)
160
+ self._overwriteCB.toggled.connect(self._configChanged)
161
+ self._publishConfig.sigConfigChanged.connect(self.sigConfigChanged)
162
+ self._binningQCB.currentIndexChanged.connect(self._configChanged)
163
+
164
+ def getOutputFormat(self) -> OutputFormat:
165
+ return OutputFormat.from_value(self._outputFormat.currentText())
166
+
167
+ def setOutputFormat(self, format: OutputFormat):
168
+ format = OutputFormat.from_value(format)
169
+ self._outputFormat.setCurrentText(format.value)
170
+
171
+ def getBinning(self) -> Binning:
172
+ return Binning.from_value(self._binningQCB.currentText())
173
+
174
+ def setBinning(self, binning: Binning):
175
+ binning = Binning.from_value(binning)
176
+ self._binningQCB.setCurrentText(binning.value)
177
+
178
+ def getConfiguration(self):
179
+ return concatenate_dict(
180
+ self._publishConfig.getConfiguration(),
181
+ {
182
+ "output_format": self.getOutputFormat().value,
183
+ "output_location_mode": self._outputDirWidget.getOutputFolderMode().value,
184
+ "custom_output": self._outputDirWidget.getOtherOutputDir(),
185
+ "overwrite": self._overwriteCB.isChecked(),
186
+ "binning": self.getBinning().value,
187
+ },
188
+ )
189
+
190
+ def setConfiguration(self, config: dict):
191
+ self._publishConfig.setConfiguration(config)
192
+ output_format = config.get("output_format", None)
193
+ if output_format is not None:
194
+ self.setOutputFormat(output_format)
195
+
196
+ output_location_mode = config.get("output_location_mode", None)
197
+ if output_location_mode is not None:
198
+ self._outputDirWidget.setOutputFolderMode(output_location_mode)
199
+
200
+ custom_output = config.get("custom_output", None)
201
+ if custom_output is not None:
202
+ self._outputDirWidget.setOtherOutputDir(custom_output)
203
+
204
+ overwrite = config.get("overwrite", None)
205
+ if overwrite is not None:
206
+ overwrite = overwrite in (True, "True", 1)
207
+ self._overwriteCB.setChecked(overwrite)
208
+
209
+ binning = config.get("binning", None)
210
+ if binning is not None:
211
+ self.setBinning(binning=binning)
212
+
213
+ def _configChanged(self, *args, **kwargs):
214
+ self.sigConfigChanged.emit()
@@ -0,0 +1,187 @@
1
+ import platform
2
+ from silx.gui import qt
3
+ from tomwer.core.scan.scanbase import TomwerScanBase
4
+ from tomwer.gui.utils.qt_utils import block_signals
5
+ from tomwer.gui.utils.buttons import PadlockButton
6
+
7
+
8
+ class PublishProcessedDataWidget(qt.QWidget):
9
+ sigConfigChanged = qt.Signal()
10
+ """emit when the configuration changed"""
11
+
12
+ KNOW_BEAMLINES = sorted(
13
+ ("bm05", "bm18", "id11", "id15a", "id16a", "id16b", "id17", "id19")
14
+ )
15
+
16
+ _TOOLTIP_PAD_LOCKS = "when receive a new scan the value will be updated if valid informations are found. If the field is lock then no update will be done automatically."
17
+
18
+ def __init__(self, parent=None) -> None:
19
+ super().__init__(parent)
20
+ self.setLayout(qt.QGridLayout())
21
+
22
+ # beamline
23
+ self._beamlineCB = qt.QComboBox(self)
24
+ self._beamlineCB.setEditable(True)
25
+ self._beamlineCB.addItems(self.KNOW_BEAMLINES)
26
+ self._beamlineCB.lineEdit().setPlaceholderText("beamline name")
27
+ self.layout().addWidget(
28
+ qt.QLabel("beamline", self),
29
+ 0,
30
+ 0,
31
+ 1,
32
+ 1,
33
+ )
34
+ self.layout().addWidget(
35
+ self._beamlineCB,
36
+ 0,
37
+ 1,
38
+ 1,
39
+ 1,
40
+ )
41
+ self._beamlinePLB = PadlockButton(self)
42
+ self._beamlinePLB.setToolTip(self._TOOLTIP_PAD_LOCKS)
43
+ self.layout().addWidget(
44
+ self._beamlinePLB,
45
+ 0,
46
+ 2,
47
+ 1,
48
+ 1,
49
+ )
50
+
51
+ # proposal
52
+ self._proposalQLE = qt.QLineEdit("", self)
53
+ self._proposalQLE.setPlaceholderText("proposal name")
54
+ self.layout().addWidget(
55
+ qt.QLabel("proposal", self),
56
+ 1,
57
+ 0,
58
+ 1,
59
+ 1,
60
+ )
61
+ self.layout().addWidget(
62
+ self._proposalQLE,
63
+ 1,
64
+ 1,
65
+ 1,
66
+ 1,
67
+ )
68
+ self._proposalPLB = PadlockButton(self)
69
+ self._proposalPLB.setToolTip(self._TOOLTIP_PAD_LOCKS)
70
+ self.layout().addWidget(
71
+ self._proposalPLB,
72
+ 1,
73
+ 2,
74
+ 1,
75
+ 1,
76
+ )
77
+
78
+ # dataset
79
+ self._datasetQLE = qt.QLineEdit("", self)
80
+ self._datasetQLE.setPlaceholderText("dataset name")
81
+ self.layout().addWidget(
82
+ qt.QLabel("dataset", self),
83
+ 2,
84
+ 0,
85
+ 1,
86
+ 1,
87
+ )
88
+ self.layout().addWidget(
89
+ self._datasetQLE,
90
+ 2,
91
+ 1,
92
+ 1,
93
+ 1,
94
+ )
95
+ self._datasetPLB = PadlockButton(self)
96
+ self._datasetPLB.setToolTip(self._TOOLTIP_PAD_LOCKS)
97
+ self.layout().addWidget(
98
+ self._datasetPLB,
99
+ 2,
100
+ 2,
101
+ 1,
102
+ 1,
103
+ )
104
+
105
+ # set up
106
+ default_beamline = self.getDefaultBeamline()
107
+ if default_beamline is not None:
108
+ self._beamlineCB.setCurrentText(default_beamline)
109
+
110
+ # connect signal / slot
111
+ self._beamlinePLB.toggled.connect(self._configChanged)
112
+ self._proposalPLB.toggled.connect(self._configChanged)
113
+ self._datasetPLB.toggled.connect(self._configChanged)
114
+ self._beamlineCB.currentTextChanged.connect(self._configChanged)
115
+ self._proposalQLE.textEdited.connect(self._configChanged)
116
+ self._datasetQLE.textEdited.connect(self._configChanged)
117
+
118
+ @staticmethod
119
+ def getDefaultBeamline():
120
+ hostname = platform.node()
121
+ for beamline in PublishProcessedDataWidget.KNOW_BEAMLINES:
122
+ if beamline in hostname:
123
+ return beamline
124
+
125
+ return None
126
+
127
+ def set_auto_update(self, update: bool):
128
+ self._beamlinePLB.setChecked(not update)
129
+ self._proposalPLB.setChecked(not update)
130
+ self._datasetPLB.setChecked(not update)
131
+
132
+ def _configChanged(self, *args, **kwargs):
133
+ self.sigConfigChanged.emit()
134
+
135
+ def getConfiguration(self) -> dict:
136
+ return {
137
+ "beamline_auto_update": not self._beamlinePLB.isChecked(),
138
+ "dataset_auto_update": not self._datasetPLB.isChecked(),
139
+ "proposal_auto_update": not self._proposalPLB.isChecked(),
140
+ "beamline": self._beamlineCB.currentText(),
141
+ "dataset": self._datasetQLE.text(),
142
+ "proposal": self._proposalQLE.text(),
143
+ }
144
+
145
+ def setConfiguration(self, configuration: dict):
146
+ with block_signals(self):
147
+ # handle beamline
148
+ beamline = configuration.get("beamline", None)
149
+ if beamline is not None:
150
+ self._beamlineCB.setCurrentText(beamline)
151
+ beamline_auto_update = configuration.get("beamline_auto_update", None)
152
+ if beamline_auto_update is not None:
153
+ self._beamlinePLB.setChecked(not beamline_auto_update)
154
+
155
+ # handle dataset
156
+ dataset = configuration.get("dataset", None)
157
+ if dataset is not None:
158
+ self._datasetQLE.setText(dataset)
159
+ dataset_auto_update = configuration.get("dataset_auto_update", None)
160
+ if dataset_auto_update is not None:
161
+ self._datasetPLB.setChecked(not dataset_auto_update)
162
+
163
+ # handle proposal
164
+ proposal = configuration.get("proposal", None)
165
+ if proposal is not None:
166
+ self._proposalQLE.setText(proposal)
167
+ proposal_auto_update = configuration.get("proposal_auto_update", None)
168
+ if proposal_auto_update is not None:
169
+ self._proposalPLB.setChecked(not proposal_auto_update)
170
+
171
+ self._configChanged()
172
+
173
+ def setScan(self, scan: TomwerScanBase):
174
+ if not isinstance(scan, TomwerScanBase):
175
+ raise TypeError(
176
+ f"scan is expected to be an instance of {TomwerScanBase}, {type(scan)} provided instead"
177
+ )
178
+
179
+ new_config = {}
180
+ if not self._proposalPLB.isChecked():
181
+ new_config["proposal"] = scan.get_proposal_name()
182
+ if not self._beamlinePLB.isChecked():
183
+ new_config["beamline"] = scan.instrument_name
184
+ if not self._datasetPLB.isChecked():
185
+ new_config["dataset"] = scan.sample_name
186
+
187
+ self.setConfiguration(new_config)