OpenREM 1.0.0b2__py3-none-any.whl → 1.0.0b3__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 (279) hide show
  1. openrem/locale/de/LC_MESSAGES/django.po +1060 -1059
  2. openrem/locale/django.pot +973 -972
  3. openrem/locale/es_MX/LC_MESSAGES/django.po +1049 -1048
  4. openrem/locale/it/LC_MESSAGES/django.po +1044 -1043
  5. openrem/locale/lt/LC_MESSAGES/django.po +989 -988
  6. openrem/locale/nb_NO/LC_MESSAGES/django.po +985 -984
  7. openrem/locale/pt_BR/LC_MESSAGES/django.po +1003 -1002
  8. openrem/manage.py +10 -10
  9. openrem/openremproject/__init__.py +1 -1
  10. openrem/openremproject/local_settings.py.linux +128 -128
  11. openrem/openremproject/local_settings.py.windows +144 -144
  12. openrem/openremproject/local_settings.py.windows-sqlite3 +129 -129
  13. openrem/openremproject/settings.py +278 -278
  14. openrem/openremproject/urls.py +32 -32
  15. openrem/openremproject/wsgi.py.example +28 -28
  16. openrem/remapp/__init__.py +2 -2
  17. openrem/remapp/admin.py +31 -31
  18. openrem/remapp/exports/ct_export.py +780 -753
  19. openrem/remapp/exports/dx_export.py +817 -805
  20. openrem/remapp/exports/export_common.py +931 -951
  21. openrem/remapp/exports/export_common_pandas.py +2422 -0
  22. openrem/remapp/exports/exportviews.py +815 -860
  23. openrem/remapp/exports/mg_csv_nhsbsp.py +292 -292
  24. openrem/remapp/exports/mg_export.py +673 -510
  25. openrem/remapp/exports/nm_export.py +796 -575
  26. openrem/remapp/exports/rf_export.py +1418 -1431
  27. openrem/remapp/extractors/ct_philips.py +424 -414
  28. openrem/remapp/extractors/ct_toshiba.py +2116 -2108
  29. openrem/remapp/extractors/dx.py +1033 -952
  30. openrem/remapp/extractors/extract_common.py +817 -817
  31. openrem/remapp/extractors/import_views.py +426 -426
  32. openrem/remapp/extractors/mam.py +685 -672
  33. openrem/remapp/extractors/nm_image.py +439 -431
  34. openrem/remapp/extractors/ptsizecsv2db.py +368 -368
  35. openrem/remapp/extractors/rdsr.py +667 -654
  36. openrem/remapp/extractors/rdsr_methods.py +1771 -1768
  37. openrem/remapp/extractors/rrdsr_methods.py +630 -622
  38. openrem/remapp/fixtures/openskin_safelist.json +11 -11
  39. openrem/remapp/forms.py +2286 -2277
  40. openrem/remapp/interface/chart_functions.py +2412 -2393
  41. openrem/remapp/interface/mod_filters.py +1241 -1243
  42. openrem/remapp/migrations/0001_initial.py.1-0-upgrade +1043 -1043
  43. openrem/remapp/models.py +3418 -3407
  44. openrem/remapp/netdicom/dicomviews.py +681 -683
  45. openrem/remapp/netdicom/qrscu.py +2646 -2646
  46. openrem/remapp/netdicom/tools.py +134 -134
  47. openrem/remapp/static/css/bootstrap-theme.css +587 -587
  48. openrem/remapp/static/css/bootstrap-theme.min.css +4 -4
  49. openrem/remapp/static/css/bootstrap.css +6800 -6800
  50. openrem/remapp/static/css/bootstrap.min.css +4 -4
  51. openrem/remapp/static/css/datepicker3.css +790 -790
  52. openrem/remapp/static/css/jquery.qtip.min.css +2 -2
  53. openrem/remapp/static/css/openrem-extra.css +442 -442
  54. openrem/remapp/static/css/openrem.css +96 -96
  55. openrem/remapp/static/css/registration.css +34 -34
  56. openrem/remapp/static/fonts/glyphicons-halflings-regular.svg +287 -287
  57. openrem/remapp/static/js/bootstrap-datepicker.js +1671 -1671
  58. openrem/remapp/static/js/bootstrap.js +2363 -2363
  59. openrem/remapp/static/js/bootstrap.min.js +6 -6
  60. openrem/remapp/static/js/charts/chartCommonFunctions.js +75 -75
  61. openrem/remapp/static/js/charts/chartFullScreen.js +41 -41
  62. openrem/remapp/static/js/charts/ctChartAjax.js +331 -331
  63. openrem/remapp/static/js/charts/dxChartAjax.js +290 -290
  64. openrem/remapp/static/js/charts/mgChartAjax.js +144 -144
  65. openrem/remapp/static/js/charts/nmChartAjax.js +64 -64
  66. openrem/remapp/static/js/charts/plotly-2.35.2.min.js +8 -0
  67. openrem/remapp/static/js/charts/rfChartAjax.js +128 -128
  68. openrem/remapp/static/js/chroma.min.js +32 -32
  69. openrem/remapp/static/js/datepicker.js +5 -5
  70. openrem/remapp/static/js/dicom.js +115 -115
  71. openrem/remapp/static/js/django_reverse/reverse.js +13 -13
  72. openrem/remapp/static/js/formatDate.js +7 -7
  73. openrem/remapp/static/js/html5shiv.min.js +8 -8
  74. openrem/remapp/static/js/jquery-1.11.0.min.js +4 -4
  75. openrem/remapp/static/js/npm.js +12 -12
  76. openrem/remapp/static/js/respond.min.js +4 -4
  77. openrem/remapp/static/js/skin-dose-maps/jquery.qtip.min.js +4 -4
  78. openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMap3dHUDObject.js +112 -112
  79. openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMap3dObject.js +367 -367
  80. openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMap3dPersonObject.js +158 -158
  81. openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapColourScaleObject.js +153 -153
  82. openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapObject.js +367 -367
  83. openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapping.js +584 -584
  84. openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMapping3d.js +255 -255
  85. openrem/remapp/static/js/skin-dose-maps/rfSkinDoseMappingAjax.js +267 -212
  86. openrem/remapp/static/js/skin-dose-maps/three.min.js +835 -835
  87. openrem/remapp/static/js/sorttable.js +495 -495
  88. openrem/remapp/templates/base.html +253 -253
  89. openrem/remapp/templates/registration/changepassword.html +25 -25
  90. openrem/remapp/templates/registration/changepassworddone.html +12 -12
  91. openrem/remapp/templates/registration/login.html +42 -42
  92. openrem/remapp/templates/remapp/backgroundtaskmaximumrows_form.html +29 -29
  93. openrem/remapp/templates/remapp/base.html +1 -1
  94. openrem/remapp/templates/remapp/ctdetail.html +235 -235
  95. openrem/remapp/templates/remapp/ctfiltered.html +310 -310
  96. openrem/remapp/templates/remapp/dicomdeletesettings_form.html +31 -31
  97. openrem/remapp/templates/remapp/dicomqr.html +147 -147
  98. openrem/remapp/templates/remapp/dicomquerydetails.html +83 -83
  99. openrem/remapp/templates/remapp/dicomqueryimages.html +49 -49
  100. openrem/remapp/templates/remapp/dicomqueryseries.html +109 -109
  101. openrem/remapp/templates/remapp/dicomquerysummary.html +48 -48
  102. openrem/remapp/templates/remapp/dicomremoteqr_confirm_delete.html +60 -60
  103. openrem/remapp/templates/remapp/dicomremoteqr_form.html +32 -32
  104. openrem/remapp/templates/remapp/dicomstorescp_confirm_delete.html +53 -53
  105. openrem/remapp/templates/remapp/dicomstorescp_form.html +48 -48
  106. openrem/remapp/templates/remapp/dicomsummary.html +257 -257
  107. openrem/remapp/templates/remapp/displaychartoptions.html +184 -184
  108. openrem/remapp/templates/remapp/displayhomepageoptions.html +57 -57
  109. openrem/remapp/templates/remapp/displayname-count.html +6 -6
  110. openrem/remapp/templates/remapp/displayname-last-date.html +3 -3
  111. openrem/remapp/templates/remapp/displayname-modality.html +86 -105
  112. openrem/remapp/templates/remapp/displayname-skinmap.html +18 -18
  113. openrem/remapp/templates/remapp/displaynameupdate.html +100 -100
  114. openrem/remapp/templates/remapp/displaynameview.html +222 -219
  115. openrem/remapp/templates/remapp/dxdetail.html +176 -176
  116. openrem/remapp/templates/remapp/dxfiltered.html +324 -324
  117. openrem/remapp/templates/remapp/exports-active.html +25 -25
  118. openrem/remapp/templates/remapp/exports-complete.html +35 -35
  119. openrem/remapp/templates/remapp/exports-error.html +26 -26
  120. openrem/remapp/templates/remapp/exports-queue.html +18 -18
  121. openrem/remapp/templates/remapp/exports.html +191 -191
  122. openrem/remapp/templates/remapp/failed_summary_list.html +27 -27
  123. openrem/remapp/templates/remapp/filteredbase.html +162 -162
  124. openrem/remapp/templates/remapp/highdosemetricalertsettings_form.html +76 -76
  125. openrem/remapp/templates/remapp/home-list-modalities.html +94 -94
  126. openrem/remapp/templates/remapp/home.html +202 -202
  127. openrem/remapp/templates/remapp/list_filters.html +24 -24
  128. openrem/remapp/templates/remapp/mgdetail.html +160 -138
  129. openrem/remapp/templates/remapp/mgfiltered.html +311 -311
  130. openrem/remapp/templates/remapp/nmdetail.html +300 -300
  131. openrem/remapp/templates/remapp/nmfiltered.html +255 -255
  132. openrem/remapp/templates/remapp/notpatient.html +190 -190
  133. openrem/remapp/templates/remapp/notpatientindicators_form_base.html +81 -81
  134. openrem/remapp/templates/remapp/notpatientindicatorsid_confirm_delete.html +54 -54
  135. openrem/remapp/templates/remapp/notpatientindicatorsid_form.html +23 -23
  136. openrem/remapp/templates/remapp/notpatientindicatorsname_confirm_delete.html +54 -54
  137. openrem/remapp/templates/remapp/notpatientindicatorsname_form.html +23 -23
  138. openrem/remapp/templates/remapp/notpatientindicatorsname_form_base.html +85 -85
  139. openrem/remapp/templates/remapp/openskinsafelist_add.html +130 -130
  140. openrem/remapp/templates/remapp/openskinsafelist_confirm_delete.html +100 -100
  141. openrem/remapp/templates/remapp/openskinsafelist_form.html +207 -207
  142. openrem/remapp/templates/remapp/patientidsettings_form.html +83 -83
  143. openrem/remapp/templates/remapp/populate_summary_progress.html +83 -83
  144. openrem/remapp/templates/remapp/populate_summary_progress_error.html +36 -36
  145. openrem/remapp/templates/remapp/review_failed_imports.html +157 -157
  146. openrem/remapp/templates/remapp/review_failed_study.html +41 -41
  147. openrem/remapp/templates/remapp/review_studies_delete_button.html +20 -20
  148. openrem/remapp/templates/remapp/review_study.html +19 -19
  149. openrem/remapp/templates/remapp/review_summary_list.html +245 -245
  150. openrem/remapp/templates/remapp/rf_dose_alert_email_template.html +14 -1
  151. openrem/remapp/templates/remapp/rfalertnotificationsview.html +59 -59
  152. openrem/remapp/templates/remapp/rfdetail.html +547 -543
  153. openrem/remapp/templates/remapp/rfdetailbase.html +18 -18
  154. openrem/remapp/templates/remapp/rffiltered.html +404 -404
  155. openrem/remapp/templates/remapp/sizeimports.html +119 -119
  156. openrem/remapp/templates/remapp/sizeprocess.html +96 -96
  157. openrem/remapp/templates/remapp/sizeupload.html +110 -110
  158. openrem/remapp/templates/remapp/skindosemapcalcsettings_form.html +28 -28
  159. openrem/remapp/templates/remapp/standardname-modality.html +69 -69
  160. openrem/remapp/templates/remapp/standardnames_confirm_delete.html +71 -71
  161. openrem/remapp/templates/remapp/standardnames_form.html +87 -87
  162. openrem/remapp/templates/remapp/standardnamesettings_form.html +41 -41
  163. openrem/remapp/templates/remapp/standardnamesrefreshall.html +92 -92
  164. openrem/remapp/templates/remapp/standardnameview.html +103 -103
  165. openrem/remapp/templates/remapp/study_confirm_delete.html +147 -147
  166. openrem/remapp/templates/remapp/task_admin.html +265 -265
  167. openrem/remapp/templates/remapp/tasks.html +76 -76
  168. openrem/remapp/templatetags/formfilters.py +13 -13
  169. openrem/remapp/templatetags/proper_paginate.py +38 -38
  170. openrem/remapp/templatetags/remappduration.py +36 -36
  171. openrem/remapp/templatetags/sigdig.py +38 -38
  172. openrem/remapp/templatetags/sort_class_property_value.py +15 -15
  173. openrem/remapp/templatetags/update_variable.py +20 -20
  174. openrem/remapp/templatetags/url_replace.py +25 -25
  175. openrem/remapp/tests/test_charts_common.py +202 -202
  176. openrem/remapp/tests/test_charts_ct.py +7111 -7111
  177. openrem/remapp/tests/test_charts_dx.py +3513 -3513
  178. openrem/remapp/tests/test_charts_mg.py +1116 -1115
  179. openrem/remapp/tests/test_dcmdatetime.py +189 -189
  180. openrem/remapp/tests/test_dicom_qr.py +2580 -2580
  181. openrem/remapp/tests/test_display_name.py +274 -274
  182. openrem/remapp/tests/test_export_ct_xlsx.py +272 -248
  183. openrem/remapp/tests/test_export_dx_xlsx.py +137 -134
  184. openrem/remapp/tests/test_export_mammo_csv.py +242 -242
  185. openrem/remapp/tests/test_export_rf_xlsx.py +246 -246
  186. openrem/remapp/tests/test_files/DX-Im-DRGEM.dcm +0 -0
  187. openrem/remapp/tests/test_files/MG-RDSR-GEPristina-2D.dcm +0 -0
  188. openrem/remapp/tests/test_files/MG-RDSR-GEPristina-DBT.dcm +0 -0
  189. openrem/remapp/tests/test_files/MG-RDSR-Giotto-DBT.dcm +0 -0
  190. openrem/remapp/tests/test_files/skin_map_alphenix.py +590 -590
  191. openrem/remapp/tests/test_files/skin_map_zee.py +354 -354
  192. openrem/remapp/tests/test_filters_ct.py +321 -321
  193. openrem/remapp/tests/test_filters_dx.py +92 -92
  194. openrem/remapp/tests/test_filters_mammo.py +183 -183
  195. openrem/remapp/tests/test_filters_rf.py +118 -118
  196. openrem/remapp/tests/test_get_values.py +72 -72
  197. openrem/remapp/tests/test_hash_id.py +65 -65
  198. openrem/remapp/tests/test_import_ct_esr_ge.py +3034 -3034
  199. openrem/remapp/tests/test_import_ct_philips_rdsr.py +42 -42
  200. openrem/remapp/tests/test_import_ct_rdsr_multiple.py +256 -256
  201. openrem/remapp/tests/test_import_ct_rdsr_siemens.py +827 -827
  202. openrem/remapp/tests/test_import_ct_rdsr_spectrumdynamics.py +91 -91
  203. openrem/remapp/tests/test_import_ct_rdsr_toshiba_dosecheck.py +67 -67
  204. openrem/remapp/tests/test_import_ct_rdsr_toshiba_multivaluesd.py +33 -33
  205. openrem/remapp/tests/test_import_ct_rdsr_toshiba_pixelmed.py +118 -118
  206. openrem/remapp/tests/test_import_ct_sc_philips.py +44 -44
  207. openrem/remapp/tests/test_import_dual_rdsr.py +110 -110
  208. openrem/remapp/tests/test_import_dx.py +1267 -1191
  209. openrem/remapp/tests/test_import_dx_rdsr.py +1250 -1253
  210. openrem/remapp/tests/test_import_mam.py +438 -438
  211. openrem/remapp/tests/test_import_mg_im_hol_proj.py +46 -46
  212. openrem/remapp/tests/test_import_mg_rdsr.py +586 -586
  213. openrem/remapp/tests/test_import_nm_image.py +420 -420
  214. openrem/remapp/tests/test_import_nm_siemens_rdsr.py +396 -396
  215. openrem/remapp/tests/test_import_px.py +161 -161
  216. openrem/remapp/tests/test_import_rf_rdsr.py +420 -418
  217. openrem/remapp/tests/test_missing_date.py +42 -42
  218. openrem/remapp/tests/test_not_patient.py +60 -60
  219. openrem/remapp/tests/test_openskin.py +272 -272
  220. openrem/remapp/tests/test_patient_id_settings.py +72 -72
  221. openrem/remapp/tests/test_pt_size_import.py +232 -232
  222. openrem/remapp/tests/test_rf_detail.py +113 -113
  223. openrem/remapp/tests/test_rf_high_dose_alert.py +361 -361
  224. openrem/remapp/tools/background.py +361 -361
  225. openrem/remapp/tools/check_standard_name_status.py +47 -0
  226. openrem/remapp/tools/check_uid.py +70 -70
  227. openrem/remapp/tools/dcmdatetime.py +248 -248
  228. openrem/remapp/tools/default_import.py +44 -47
  229. openrem/remapp/tools/get_values.py +230 -230
  230. openrem/remapp/tools/hash_id.py +58 -58
  231. openrem/remapp/tools/make_skin_map.py +448 -406
  232. openrem/remapp/tools/not_patient_indicators.py +72 -72
  233. openrem/remapp/tools/openskin/calc_exp_map.py +173 -173
  234. openrem/remapp/tools/openskin/geomclass.py +475 -475
  235. openrem/remapp/tools/openskin/geomfunc.py +433 -432
  236. openrem/remapp/tools/openskin/skinmap.py +417 -417
  237. openrem/remapp/tools/populate_summary.py +185 -193
  238. openrem/remapp/tools/save_skin_map_structure.py +73 -73
  239. openrem/remapp/tools/send_high_dose_alert_emails.py +238 -207
  240. openrem/remapp/urls.py +456 -448
  241. openrem/remapp/version.py +11 -11
  242. openrem/remapp/views.py +1147 -1052
  243. openrem/remapp/views_admin.py +3876 -3936
  244. openrem/remapp/views_charts_ct.py +2110 -2058
  245. openrem/remapp/views_charts_dx.py +1906 -1836
  246. openrem/remapp/views_charts_mg.py +1349 -1196
  247. openrem/remapp/views_charts_nm.py +535 -535
  248. openrem/remapp/views_charts_rf.py +1219 -1241
  249. openrem/remapp/views_openskin.py +379 -384
  250. openrem/sample-config/openrem-consumer.service +12 -12
  251. openrem/sample-config/openrem-gunicorn.service +13 -13
  252. openrem/sample-config/openrem-server +14 -13
  253. openrem/sample-config/openrem_orthanc_config_linux.lua +454 -454
  254. openrem/sample-config/openrem_orthanc_config_windows.lua +455 -455
  255. openrem/sample-config/queue-init.bat +73 -73
  256. openrem/scripts/openrem_ctphilips.py +25 -25
  257. openrem/scripts/openrem_cttoshiba.py +28 -28
  258. openrem/scripts/openrem_dx.py +22 -22
  259. openrem/scripts/openrem_mg.py +22 -22
  260. openrem/scripts/openrem_nm.py +22 -22
  261. openrem/scripts/openrem_ptsizecsv.py +17 -17
  262. openrem/scripts/openrem_qr.py +12 -12
  263. openrem/scripts/openrem_rdsr.py +25 -25
  264. {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info}/METADATA +39 -29
  265. openrem-1.0.0b3.dist-info/RECORD +379 -0
  266. {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info}/WHEEL +1 -1
  267. {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info/licenses}/COPYING-GPLv3 +674 -674
  268. {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info/licenses}/LICENSE +22 -22
  269. OpenREM-1.0.0b2.dist-info/RECORD +0 -373
  270. openrem/remapp/static/js/charts/plotly-2.17.1.min.js +0 -8
  271. {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_ctphilips.py +0 -0
  272. {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_cttoshiba.py +0 -0
  273. {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_dx.py +0 -0
  274. {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_mg.py +0 -0
  275. {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_nm.py +0 -0
  276. {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_ptsizecsv.py +0 -0
  277. {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_qr.py +0 -0
  278. {OpenREM-1.0.0b2.data → openrem-1.0.0b3.data}/scripts/openrem_rdsr.py +0 -0
  279. {OpenREM-1.0.0b2.dist-info → openrem-1.0.0b3.dist-info}/top_level.txt +0 -0
openrem/remapp/forms.py CHANGED
@@ -1,2277 +1,2286 @@
1
- # pylint: disable=too-many-lines
2
- # This Python file uses the following encoding: utf-8
3
- # OpenREM - Radiation Exposure Monitoring tools for the physicist
4
- # Copyright (C) 2019 The Royal Marsden NHS Foundation Trust
5
- #
6
- # This program is free software: you can redistribute it and/or modify
7
- # it under the terms of the GNU General Public License as published by
8
- # the Free Software Foundation, either version 3 of the License, or
9
- # (at your option) any later version.
10
- #
11
- # This program is distributed in the hope that it will be useful,
12
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- # GNU General Public License for more details.
15
- #
16
- # Additional permission under section 7 of GPLv3:
17
- # You shall not make any use of the name of The Royal Marsden NHS
18
- # Foundation trust in connection with this Program in any press or
19
- # other public announcement without the prior written consent of
20
- # The Royal Marsden NHS Foundation Trust.
21
- #
22
- # You should have received a copy of the GNU General Public License
23
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
24
-
25
- """
26
- .. module:: forms
27
- :synopsis: Django forms definitions
28
- """
29
-
30
- import os
31
- import logging
32
- import operator
33
- from functools import reduce
34
-
35
- from django import forms
36
- from django.db.models import Q
37
- from django.contrib.admin.widgets import FilteredSelectMultiple
38
- from django.conf import settings
39
- from django.utils.safestring import mark_safe
40
- from django.urls import reverse
41
- from django.utils.translation import gettext as _
42
- from crispy_forms.helper import FormHelper
43
- from crispy_forms.layout import Layout, Submit, HTML, Div
44
- from crispy_forms.bootstrap import (
45
- FormActions,
46
- PrependedText,
47
- InlineCheckboxes,
48
- Accordion,
49
- AccordionGroup,
50
- )
51
-
52
- from .models import (
53
- DicomDeleteSettings,
54
- DicomRemoteQR,
55
- DicomStoreSCP,
56
- SkinDoseMapCalcSettings,
57
- NotPatientIndicatorsName,
58
- NotPatientIndicatorsID,
59
- HighDoseMetricAlertSettings,
60
- CommonVariables,
61
- OpenSkinSafeList,
62
- StandardNames,
63
- StandardNameSettings,
64
- GeneralStudyModuleAttr,
65
- CtIrradiationEventData,
66
- IrradEventXRayData,
67
- BackgroundTaskMaximumRows,
68
- )
69
-
70
- logger = logging.getLogger()
71
-
72
-
73
- class SizeUploadForm(forms.Form):
74
- """Form for patient size csv file upload"""
75
-
76
- sizefile = forms.FileField(label=_("Select a file"))
77
-
78
-
79
- class SizeHeadersForm(forms.Form):
80
- """Form for csv column header patient size imports through the web interface"""
81
-
82
- height_field = forms.ChoiceField(choices="")
83
- weight_field = forms.ChoiceField(choices="")
84
- id_field = forms.ChoiceField(choices="")
85
- id_type = forms.ChoiceField(choices="")
86
- overwrite = forms.BooleanField(initial=False, required=False)
87
-
88
- def __init__(self, my_choice=None, **kwargs):
89
- super(SizeHeadersForm, self).__init__(**kwargs)
90
- if my_choice:
91
- self.fields["height_field"] = forms.ChoiceField(
92
- choices=my_choice, widget=forms.Select(attrs={"class": "form-control"})
93
- )
94
- self.fields["weight_field"] = forms.ChoiceField(
95
- choices=my_choice, widget=forms.Select(attrs={"class": "form-control"})
96
- )
97
- self.fields["id_field"] = forms.ChoiceField(
98
- choices=my_choice, widget=forms.Select(attrs={"class": "form-control"})
99
- )
100
- ID_TYPES = (
101
- ("acc-no", _("Accession Number")),
102
- ("si-uid", _("Study instance UID")),
103
- )
104
- self.fields["id_type"] = forms.ChoiceField(
105
- choices=ID_TYPES, widget=forms.Select(attrs={"class": "form-control"})
106
- )
107
-
108
-
109
- class itemsPerPageForm(forms.Form):
110
- itemsPerPage = forms.ChoiceField(
111
- label=_("Items per page"),
112
- choices=CommonVariables.ITEMS_PER_PAGE,
113
- required=False,
114
- )
115
-
116
-
117
- class DXChartOptionsForm(forms.Form):
118
- """Form for DX chart options"""
119
-
120
- plotCharts = forms.BooleanField(label=_("Plot charts?"), required=False)
121
- plotCharts.group = "PlotCharts"
122
- plotDXAcquisitionMeanDAPOverTimePeriod = forms.ChoiceField(
123
- label="Time period", choices=CommonVariables.TIME_PERIOD, required=False
124
- )
125
- plotDXAcquisitionMeanDAPOverTimePeriod.group = "General"
126
- plotAverageChoice = forms.MultipleChoiceField(
127
- label="Average plots",
128
- choices=CommonVariables.AVERAGES,
129
- required=False,
130
- widget=forms.CheckboxSelectMultiple(attrs={"class": "CheckboxSelectMultiple"}),
131
- )
132
- plotAverageChoice.group = "General"
133
- plotGrouping = forms.ChoiceField(
134
- label=mark_safe("Grouping choice"), # nosec
135
- choices=CommonVariables.CHART_GROUPING,
136
- required=False,
137
- )
138
- plotGrouping.group = "General"
139
- plotSeriesPerSystem = forms.BooleanField(
140
- label="Plot a series per system", required=False
141
- )
142
- plotSeriesPerSystem.group = "General"
143
- plotHistograms = forms.BooleanField(
144
- label="Calculate histogram data", required=False
145
- )
146
- plotHistograms.group = "General"
147
- plotDXInitialSortingChoice = forms.ChoiceField(
148
- label="Chart sorting", choices=CommonVariables.SORTING_CHOICES, required=False
149
- )
150
- plotDXInitialSortingChoice.group = "General"
151
- plotInitialSortingDirection = forms.ChoiceField(
152
- label="Sorting direction",
153
- choices=CommonVariables.SORTING_DIRECTION,
154
- required=False,
155
- )
156
- plotInitialSortingDirection.group = "General"
157
- plotDXAcquisitionFreq = forms.BooleanField(
158
- label=_("Acquisition frequency"), required=False
159
- )
160
- plotDXAcquisitionFreq.group = "Acquisition protocol"
161
- plotDXAcquisitionMeanDAP = forms.BooleanField(
162
- label=_("Acquisition DAP"), required=False
163
- )
164
- plotDXAcquisitionMeanDAP.group = "Acquisition protocol"
165
- plotDXAcquisitionMeanmAs = forms.BooleanField(
166
- label=_("Acquisition mAs"), required=False
167
- )
168
- plotDXAcquisitionMeanmAs.group = "Acquisition protocol"
169
- plotDXAcquisitionMeankVp = forms.BooleanField(
170
- label=_("Acquisition kVp"), required=False
171
- )
172
- plotDXAcquisitionMeankVp.group = "Acquisition protocol"
173
- plotDXAcquisitionMeanDAPOverTime = forms.BooleanField(
174
- label=_("Acquisition DAP over time"), required=False
175
- )
176
- plotDXAcquisitionMeanDAPOverTime.group = "Acquisition protocol"
177
- plotDXAcquisitionMeanmAsOverTime = forms.BooleanField(
178
- label=_("Acquisition mAs over time"), required=False
179
- )
180
- plotDXAcquisitionMeanmAsOverTime.group = "Acquisition protocol"
181
- plotDXAcquisitionMeankVpOverTime = forms.BooleanField(
182
- label=_("Acquisition kVp over time"), required=False
183
- )
184
- plotDXAcquisitionMeankVpOverTime.group = "Acquisition protocol"
185
- plotDXAcquisitionDAPvsMass = forms.BooleanField(
186
- label=_("Acquisition DAP vs mass"), required=False
187
- )
188
- plotDXAcquisitionDAPvsMass.group = "Acquisition protocol"
189
- plotDXStudyFreq = forms.BooleanField(label=_("Study frequency"), required=False)
190
- plotDXStudyFreq.group = "Study description"
191
- plotDXStudyMeanDAP = forms.BooleanField(label=_("Study DAP"), required=False)
192
- plotDXStudyMeanDAP.group = "Study description"
193
- plotDXStudyDAPvsMass = forms.BooleanField(
194
- label=_("Study DAP vs mass"), required=False
195
- )
196
- plotDXStudyDAPvsMass.group = "Study description"
197
- plotDXStudyPerDayAndHour = forms.BooleanField(
198
- label=_("Study workload"), required=False
199
- )
200
- plotDXStudyPerDayAndHour.group = "Study description"
201
- plotDXRequestFreq = forms.BooleanField(
202
- label=_("Requested procedure frequency"), required=False
203
- )
204
- plotDXRequestFreq.group = "Requested procedure"
205
- plotDXRequestMeanDAP = forms.BooleanField(
206
- label=_("Requested procedure DAP"), required=False
207
- )
208
- plotDXRequestMeanDAP.group = "Requested procedure"
209
- plotDXRequestDAPvsMass = forms.BooleanField(
210
- label=_("Requested procedure DAP vs mass"), required=False
211
- )
212
- plotDXRequestDAPvsMass.group = "Requested procedure"
213
-
214
-
215
- class DXChartOptionsFormIncStandard(DXChartOptionsForm):
216
- plotDXStandardAcquisitionFreq = forms.BooleanField(
217
- label="Standard acquisition name frequency", required=False
218
- )
219
- plotDXStandardAcquisitionFreq.group = "Standard acquisition name"
220
- plotDXStandardAcquisitionMeanDAP = forms.BooleanField(
221
- label="Standard acquisition name DAP", required=False
222
- )
223
- plotDXStandardAcquisitionMeanDAP.group = "Standard acquisition name"
224
- plotDXStandardAcquisitionMeanmAs = forms.BooleanField(
225
- label="Standard acquisition name mAs", required=False
226
- )
227
- plotDXStandardAcquisitionMeanmAs.group = "Standard acquisition name"
228
- plotDXStandardAcquisitionMeankVp = forms.BooleanField(
229
- label="Standard acquisition name kVp", required=False
230
- )
231
- plotDXStandardAcquisitionMeankVp.group = "Standard acquisition name"
232
- plotDXStandardAcquisitionMeanDAPOverTime = forms.BooleanField(
233
- label="Standard acquisition name DAP over time", required=False
234
- )
235
- plotDXStandardAcquisitionMeanDAPOverTime.group = "Standard acquisition name"
236
- plotDXStandardAcquisitionMeanmAsOverTime = forms.BooleanField(
237
- label="Standard acquisition name mAs over time", required=False
238
- )
239
- plotDXStandardAcquisitionMeanmAsOverTime.group = "Standard acquisition name"
240
- plotDXStandardAcquisitionMeankVpOverTime = forms.BooleanField(
241
- label="Standard acquisition name kVp over time", required=False
242
- )
243
- plotDXStandardAcquisitionMeankVpOverTime.group = "Standard acquisition name"
244
- plotDXStandardAcquisitionDAPvsMass = forms.BooleanField(
245
- label="Standard acquisition name DAP vs mass", required=False
246
- )
247
- plotDXStandardAcquisitionDAPvsMass.group = "Standard acquisition name"
248
-
249
- plotDXStandardStudyFreq = forms.BooleanField(
250
- label="Standard study name frequency", required=False
251
- )
252
- plotDXStandardStudyFreq.group = "Standard study name"
253
- plotDXStandardStudyMeanDAP = forms.BooleanField(
254
- label="Standard study name DAP", required=False
255
- )
256
- plotDXStandardStudyMeanDAP.group = "Standard study name"
257
- plotDXStandardStudyDAPvsMass = forms.BooleanField(
258
- label="Standard study name DAP vs mass", required=False
259
- )
260
- plotDXStandardStudyDAPvsMass.group = "Standard study name"
261
- plotDXStandardStudyPerDayAndHour = forms.BooleanField(
262
- label="Standard study name workload", required=False
263
- )
264
- plotDXStandardStudyPerDayAndHour.group = "Standard study name"
265
-
266
-
267
- class CTChartOptionsForm(forms.Form):
268
- """Form for CT chart options"""
269
-
270
- plotCharts = forms.BooleanField(label="Plot charts?", required=False)
271
- plotCharts.group = "PlotCharts"
272
- plotCTOverTimePeriod = forms.ChoiceField(
273
- label="Time period", choices=CommonVariables.TIME_PERIOD, required=False
274
- )
275
- plotCTOverTimePeriod.group = "General"
276
- plotAverageChoice = forms.MultipleChoiceField(
277
- label=_("Average plots"),
278
- choices=CommonVariables.AVERAGES,
279
- required=False,
280
- widget=forms.CheckboxSelectMultiple(attrs={"class": "CheckboxSelectMultiple"}),
281
- )
282
- plotAverageChoice.group = "General"
283
- plotGrouping = forms.ChoiceField(
284
- label=mark_safe(_("Grouping choice")), # nosec
285
- choices=CommonVariables.CHART_GROUPING,
286
- required=False,
287
- )
288
- plotGrouping.group = "General"
289
- plotSeriesPerSystem = forms.BooleanField(
290
- label=_("Plot a series per system"), required=False
291
- )
292
- plotSeriesPerSystem.group = "General"
293
- plotHistograms = forms.BooleanField(
294
- label=_("Calculate histogram data"), required=False
295
- )
296
- plotHistograms.group = "General"
297
- plotCTInitialSortingChoice = forms.ChoiceField(
298
- label=_("Chart sorting"),
299
- choices=CommonVariables.SORTING_CHOICES,
300
- required=False,
301
- )
302
- plotCTInitialSortingChoice.group = "General"
303
- plotInitialSortingDirection = forms.ChoiceField(
304
- label=_("Sorting direction"),
305
- choices=CommonVariables.SORTING_DIRECTION,
306
- required=False,
307
- )
308
- plotInitialSortingDirection.group = "General"
309
-
310
- plotCTAcquisitionFreq = forms.BooleanField(
311
- label=_("Acquisition frequency"), required=False
312
- )
313
- plotCTAcquisitionFreq.group = "Acquisition protocol"
314
- plotCTAcquisitionMeanDLP = forms.BooleanField(
315
- label=_("Acquisition DLP"), required=False
316
- )
317
- plotCTAcquisitionMeanDLP.group = "Acquisition protocol"
318
- plotCTAcquisitionMeanCTDI = forms.BooleanField(
319
- label=mark_safe(_("Acquisition CTDI<sub>vol</sub>")), required=False # nosec
320
- )
321
- plotCTAcquisitionMeanCTDI.group = "Acquisition protocol"
322
- plotCTAcquisitionDLPOverTime = forms.BooleanField(
323
- label=_("Acquisition DLP over time"), required=False
324
- )
325
- plotCTAcquisitionDLPOverTime.group = "Acquisition protocol"
326
- plotCTAcquisitionCTDIOverTime = forms.BooleanField(
327
- label=mark_safe(_("Acquisition CTDI<sub>vol</sub> over time")), # nosec
328
- required=False,
329
- )
330
- plotCTAcquisitionCTDIOverTime.group = "Acquisition protocol"
331
- plotCTAcquisitionDLPvsMass = forms.BooleanField(
332
- label=_("Acquisition DLP vs mass"), required=False
333
- )
334
- plotCTAcquisitionDLPvsMass.group = "Acquisition protocol"
335
- plotCTAcquisitionCTDIvsMass = forms.BooleanField(
336
- label=mark_safe(_("Acquisition CTDI<sub>vol</sub> vs mass")), # nosec
337
- required=False,
338
- )
339
- plotCTAcquisitionCTDIvsMass.group = "Acquisition protocol"
340
- plotCTAcquisitionTypes = forms.MultipleChoiceField(
341
- label=mark_safe( # nosec
342
- _(
343
- "Acquisition types to include<br/>in acquisition-level chart<br/>calculations"
344
- )
345
- ),
346
- choices=CommonVariables.CT_ACQUISITION_TYPES,
347
- required=False,
348
- widget=forms.CheckboxSelectMultiple(attrs={"class": "CheckboxSelectMultiple"}),
349
- )
350
- plotCTAcquisitionTypes.group = "Acquisition protocol"
351
-
352
- plotCTStudyFreq = forms.BooleanField(label="Study frequency", required=False)
353
- plotCTStudyFreq.group = "Study description"
354
- plotCTStudyMeanDLP = forms.BooleanField(label="Study DLP", required=False)
355
- plotCTStudyMeanDLP.group = "Study description"
356
- plotCTStudyMeanCTDI = forms.BooleanField(
357
- label=mark_safe(_("Study CTDI<sub>vol</sub>")), required=False # nosec
358
- )
359
- plotCTStudyMeanCTDI.group = "Study description"
360
- plotCTStudyNumEvents = forms.BooleanField(label="Study events", required=False)
361
- plotCTStudyNumEvents.group = "Study description"
362
- plotCTStudyMeanDLPOverTime = forms.BooleanField(
363
- label=_("Study DLP over time"), required=False
364
- )
365
- plotCTStudyMeanDLPOverTime.group = "Study description"
366
- plotCTStudyPerDayAndHour = forms.BooleanField(
367
- label=_("Study workload"), required=False
368
- )
369
- plotCTStudyPerDayAndHour.group = "Study description"
370
-
371
- plotCTRequestFreq = forms.BooleanField(
372
- label=_("Requested procedure frequency"), required=False
373
- )
374
- plotCTRequestFreq.group = "Requested procedure"
375
- plotCTRequestMeanDLP = forms.BooleanField(
376
- label=_("Requested procedure DLP"), required=False
377
- )
378
- plotCTRequestMeanDLP.group = "Requested procedure"
379
- plotCTRequestNumEvents = forms.BooleanField(
380
- label=_("Requested procedure events"), required=False
381
- )
382
- plotCTRequestNumEvents.group = "Requested procedure"
383
- plotCTRequestDLPOverTime = forms.BooleanField(
384
- label=_("Requested procedure DLP over time"), required=False
385
- )
386
- plotCTRequestDLPOverTime.group = "Requested procedure"
387
-
388
-
389
- class CTChartOptionsFormIncStandard(CTChartOptionsForm):
390
- plotCTStandardAcquisitionFreq = forms.BooleanField(
391
- label="Standard acquisition name frequency", required=False
392
- )
393
- plotCTStandardAcquisitionFreq.group = "Standard acquisition name"
394
- plotCTStandardAcquisitionMeanDLP = forms.BooleanField(
395
- label="Standard acquisition name DLP", required=False
396
- )
397
- plotCTStandardAcquisitionMeanDLP.group = "Standard acquisition name"
398
- plotCTStandardAcquisitionMeanCTDI = forms.BooleanField(
399
- label=mark_safe("Standard acquisition name CTDI<sub>vol</sub>"), # nosec
400
- required=False,
401
- )
402
- plotCTStandardAcquisitionMeanCTDI.group = "Standard acquisition name"
403
- plotCTStandardAcquisitionDLPOverTime = forms.BooleanField(
404
- label="Standard acquisition name DLP over time", required=False
405
- )
406
- plotCTStandardAcquisitionDLPOverTime.group = "Standard acquisition name"
407
- plotCTStandardAcquisitionCTDIOverTime = forms.BooleanField(
408
- label=mark_safe( # nosec
409
- "Standard acquisition name CTDI<sub>vol</sub> over time"
410
- ),
411
- required=False,
412
- )
413
- plotCTStandardAcquisitionCTDIOverTime.group = "Standard acquisition name"
414
- plotCTStandardAcquisitionDLPvsMass = forms.BooleanField(
415
- label="Standard acquisition name DLP vs mass", required=False
416
- )
417
- plotCTStandardAcquisitionDLPvsMass.group = "Standard acquisition name"
418
- plotCTStandardAcquisitionCTDIvsMass = forms.BooleanField(
419
- label=mark_safe( # nosec
420
- "Standard acquisition name CTDI<sub>vol</sub> vs mass"
421
- ),
422
- required=False,
423
- )
424
- plotCTStandardAcquisitionCTDIvsMass.group = "Standard acquisition name"
425
-
426
- plotCTStandardStudyFreq = forms.BooleanField(
427
- label="Standard study frequency", required=False
428
- )
429
- plotCTStandardStudyFreq.group = "Standard study name"
430
- plotCTStandardStudyMeanDLP = forms.BooleanField(
431
- label="Standard study DLP", required=False
432
- )
433
- plotCTStandardStudyMeanDLP.group = "Standard study name"
434
- plotCTStandardStudyNumEvents = forms.BooleanField(
435
- label="Standard study events", required=False
436
- )
437
- plotCTStandardStudyNumEvents.group = "Standard study name"
438
- plotCTStandardStudyMeanDLPOverTime = forms.BooleanField(
439
- label="Standard study DLP over time", required=False
440
- )
441
- plotCTStandardStudyMeanDLPOverTime.group = "Standard study name"
442
- plotCTStandardStudyPerDayAndHour = forms.BooleanField(
443
- label="Standard study workload", required=False
444
- )
445
- plotCTStandardStudyPerDayAndHour.group = "Standard study name"
446
-
447
-
448
- class NMChartOptionsForm(forms.Form):
449
- """
450
- Form for NM chart options
451
- """
452
-
453
- plotCharts = forms.BooleanField(label=_("Plot charts?"), required=False)
454
-
455
- plotNMStudyFreq = forms.BooleanField(label=_("Study frequency"), required=False)
456
- plotNMStudyPerDayAndHour = forms.BooleanField(
457
- label=_("Study workload"), required=False
458
- )
459
- plotNMInjectedDosePerStudy = forms.BooleanField(
460
- label=_("Injected dose per study"), required=False
461
- )
462
- plotNMInjectedDoseOverTime = forms.BooleanField(
463
- label=_("Injected dose over time"), required=False
464
- )
465
- plotNMInjectedDoseOverWeight = forms.BooleanField(
466
- label=_("Injected dose vs mass"), required=False
467
- )
468
- plotNMOverTimePeriod = forms.ChoiceField(
469
- label=_("Time period"), choices=CommonVariables.TIME_PERIOD, required=False
470
- )
471
- plotAverageChoice = forms.MultipleChoiceField(
472
- label=_("Average plots"),
473
- choices=CommonVariables.AVERAGES,
474
- required=False,
475
- widget=forms.CheckboxSelectMultiple(attrs={"class": "CheckboxSelectMultiple"}),
476
- )
477
- plotGrouping = forms.ChoiceField(
478
- label=mark_safe(_("Grouping choice")), # nosec
479
- choices=CommonVariables.CHART_GROUPING,
480
- required=False,
481
- )
482
- plotSeriesPerSystem = forms.BooleanField(
483
- label=_("Plot a series per system"), required=False
484
- )
485
- plotHistograms = forms.BooleanField(
486
- label=_("Calculate histogram data"), required=False
487
- )
488
- plotNMInitialSortingChoice = forms.ChoiceField(
489
- label=_("Chart sorting"),
490
- choices=CommonVariables.SORTING_CHOICES,
491
- required=False,
492
- )
493
- plotInitialSortingDirection = forms.ChoiceField(
494
- label=_("Sorting direction"),
495
- choices=CommonVariables.SORTING_DIRECTION,
496
- required=False,
497
- )
498
-
499
-
500
- class NMChartOptionsDisplayForm(forms.Form):
501
- """
502
- Form for NM chart display options
503
- """
504
-
505
- plotNMStudyFreq = forms.BooleanField(label=_("Study frequency"), required=False)
506
- plotNMStudyPerDayAndHour = forms.BooleanField(
507
- label=_("Study workload"), required=False
508
- )
509
- plotNMInjectedDosePerStudy = forms.BooleanField(
510
- label=_("Injected Dose per Study"), required=False
511
- )
512
- plotNMInjectedDoseOverTime = forms.BooleanField(
513
- label=_("Injected Dose over Time"), required=False
514
- )
515
- plotNMInjectedDoseOverWeight = forms.BooleanField(
516
- label=_("Injected Dose over Weight"), required=False
517
- )
518
- plotNMOverTimePeriod = forms.ChoiceField(
519
- label=_("Time period"), choices=CommonVariables.TIME_PERIOD, required=False
520
- )
521
- plotNMInitialSortingChoice = forms.ChoiceField(
522
- label=_("Chart sorting"),
523
- choices=CommonVariables.SORTING_CHOICES,
524
- required=False,
525
- )
526
-
527
-
528
- class RFChartOptionsForm(forms.Form):
529
- """Form for RF chart options"""
530
-
531
- plotCharts = forms.BooleanField(label="Plot charts?", required=False)
532
- plotCharts.group = "PlotCharts"
533
- plotRFOverTimePeriod = forms.ChoiceField(
534
- label="Time period", choices=CommonVariables.TIME_PERIOD, required=False
535
- )
536
- plotRFOverTimePeriod.group = "General"
537
- plotAverageChoice = forms.MultipleChoiceField(
538
- label=_("Average plots"),
539
- choices=CommonVariables.AVERAGES,
540
- required=False,
541
- widget=forms.CheckboxSelectMultiple(attrs={"class": "CheckboxSelectMultiple"}),
542
- )
543
- plotAverageChoice.group = "General"
544
- plotRFSplitByPhysician = forms.BooleanField(
545
- label="Split plots by physician", required=False
546
- )
547
- plotRFSplitByPhysician.group = "General"
548
- plotGrouping = forms.ChoiceField(
549
- label=mark_safe(_("Grouping choice")), # nosec
550
- choices=CommonVariables.CHART_GROUPING_RF,
551
- required=False,
552
- )
553
- plotGrouping.group = "General"
554
- plotSeriesPerSystem = forms.BooleanField(
555
- label=_("Plot a series per system"), required=False
556
- )
557
- plotSeriesPerSystem.group = "General"
558
- plotHistograms = forms.BooleanField(
559
- label=_("Calculate histogram data"), required=False
560
- )
561
- plotHistograms.group = "General"
562
- plotRFInitialSortingChoice = forms.ChoiceField(
563
- label="Chart sorting", choices=CommonVariables.SORTING_CHOICES, required=False
564
- )
565
- plotRFInitialSortingChoice.group = "General"
566
- plotInitialSortingDirection = forms.ChoiceField(
567
- label=_("Sorting direction"),
568
- choices=CommonVariables.SORTING_DIRECTION,
569
- required=False,
570
- )
571
- plotInitialSortingDirection.group = "General"
572
-
573
- plotRFStudyFreq = forms.BooleanField(label="Study frequency", required=False)
574
- plotRFStudyFreq.group = "Study description"
575
- plotRFStudyDAP = forms.BooleanField(label="Study DAP", required=False)
576
- plotRFStudyDAP.group = "Study description"
577
- plotRFStudyDAPOverTime = forms.BooleanField(
578
- label=_("Study DAP over time"), required=False
579
- )
580
- plotRFStudyDAPOverTime.group = "Study description"
581
- plotRFStudyPerDayAndHour = forms.BooleanField(
582
- label=_("Study workload"), required=False
583
- )
584
- plotRFStudyPerDayAndHour.group = "Study description"
585
-
586
- plotRFRequestFreq = forms.BooleanField(
587
- label=_("Requested procedure frequency"), required=False
588
- )
589
- plotRFRequestFreq.group = "Requested procedure"
590
- plotRFRequestDAP = forms.BooleanField(
591
- label=_("Requested procedure DAP"), required=False
592
- )
593
- plotRFRequestDAP.group = "Requested procedure"
594
- plotRFRequestDAPOverTime = forms.BooleanField(
595
- label=_("Requested procedure DAP over time"), required=False
596
- )
597
- plotRFRequestDAPOverTime.group = "Requested procedure"
598
-
599
-
600
- class RFChartOptionsFormIncStandard(RFChartOptionsForm):
601
- plotRFStandardStudyFreq = forms.BooleanField(
602
- label="Standard study name frequency", required=False
603
- )
604
- plotRFStandardStudyFreq.group = "Standard study name"
605
- plotRFStandardStudyDAP = forms.BooleanField(
606
- label="Standard study name DAP", required=False
607
- )
608
- plotRFStandardStudyDAP.group = "Standard study name"
609
- plotRFStandardStudyDAPOverTime = forms.BooleanField(
610
- label="Standard study name DAP over time", required=False
611
- )
612
- plotRFStandardStudyDAPOverTime.group = "Standard study name"
613
- plotRFStandardStudyPerDayAndHour = forms.BooleanField(
614
- label="Standard study name workload", required=False
615
- )
616
- plotRFStandardStudyPerDayAndHour.group = "Standard study name"
617
-
618
-
619
- class RFChartOptionsDisplayForm(forms.Form):
620
- """Form for RF chart display options"""
621
-
622
- plotRFStudyFreq = forms.BooleanField(label=_("Study frequency"), required=False)
623
- plotRFStudyDAP = forms.BooleanField(label=_("Study DAP"), required=False)
624
- plotRFStudyDAPOverTime = forms.BooleanField(
625
- label=_("Study DAP over time"), required=False
626
- )
627
- plotRFStudyPerDayAndHour = forms.BooleanField(
628
- label=_("Study workload"), required=False
629
- )
630
- plotRFRequestFreq = forms.BooleanField(
631
- label=_("Requested procedure frequency"), required=False
632
- )
633
- plotRFRequestDAP = forms.BooleanField(
634
- label=_("Requested procedure DAP"), required=False
635
- )
636
- plotRFRequestDAPOverTime = forms.BooleanField(
637
- label=_("Requested procedure DAP over time"), required=False
638
- )
639
- plotRFOverTimePeriod = forms.ChoiceField(
640
- label=_("Time period"), choices=CommonVariables.TIME_PERIOD, required=False
641
- )
642
- plotRFSplitByPhysician = forms.BooleanField(
643
- label=_("Split plots by physician"), required=False
644
- )
645
- plotRFInitialSortingChoice = forms.ChoiceField(
646
- label=_("Default chart sorting"),
647
- choices=CommonVariables.SORTING_CHOICES,
648
- required=False,
649
- )
650
-
651
-
652
- class RFChartOptionsDisplayFormIncStandard(RFChartOptionsDisplayForm):
653
- plotRFStandardStudyFreq = forms.BooleanField(
654
- label="Standard study name frequency", required=False
655
- )
656
- plotRFStandardStudyDAP = forms.BooleanField(
657
- label="Standard study name DAP", required=False
658
- )
659
- plotRFStandardStudyDAPOverTime = forms.BooleanField(
660
- label="Standard study name DAP over time", required=False
661
- )
662
- plotRFStandardStudyPerDayAndHour = forms.BooleanField(
663
- label="Standard study name workload", required=False
664
- )
665
-
666
- field_order = [
667
- "plotRFStudyFreq",
668
- "plotRFStudyDAP",
669
- "plotRFStudyDAPOverTime",
670
- "plotRFStudyPerDayAndHour",
671
- "plotRFRequestFreq",
672
- "plotRFRequestDAP",
673
- "plotRFRequestDAPOverTime",
674
- "plotRFStandardStudyFreq",
675
- "plotRFStandardStudyDAP",
676
- "plotRFStandardStudyDAPOverTime",
677
- "plotRFStandardStudyPerDayAndHour",
678
- "plotRFOverTimePeriod",
679
- "plotRFSplitByPhysician",
680
- "plotRFInitialSortingChoice",
681
- ]
682
-
683
-
684
- class MGChartOptionsForm(forms.Form):
685
- """Form for MG chart options"""
686
-
687
- plotCharts = forms.BooleanField(label="Plot charts?", required=False)
688
- plotCharts.group = "PlotCharts"
689
- plotMGOverTimePeriod = forms.ChoiceField(
690
- label=_("Time period"), choices=CommonVariables.TIME_PERIOD, required=False
691
- )
692
- plotMGOverTimePeriod.group = "General"
693
- plotAverageChoice = forms.MultipleChoiceField(
694
- label=_("Average plots"),
695
- choices=CommonVariables.AVERAGES,
696
- required=False,
697
- widget=forms.CheckboxSelectMultiple(attrs={"class": "CheckboxSelectMultiple"}),
698
- )
699
- plotAverageChoice.group = "General"
700
- plotGrouping = forms.ChoiceField(
701
- label=mark_safe(_("Grouping choice")), # nosec
702
- choices=CommonVariables.CHART_GROUPING,
703
- required=False,
704
- )
705
- plotGrouping.group = "General"
706
- plotSeriesPerSystem = forms.BooleanField(
707
- label=_("Plot a series per system"), required=False
708
- )
709
- plotSeriesPerSystem.group = "General"
710
- plotHistograms = forms.BooleanField(
711
- label=_("Calculate histogram data"), required=False
712
- )
713
- plotHistograms.group = "General"
714
- plotMGInitialSortingChoice = forms.ChoiceField(
715
- label=_("Chart sorting"),
716
- choices=CommonVariables.SORTING_CHOICES,
717
- required=False,
718
- )
719
- plotMGInitialSortingChoice.group = "General"
720
- plotInitialSortingDirection = forms.ChoiceField(
721
- label=_("Sorting direction"),
722
- choices=CommonVariables.SORTING_DIRECTION,
723
- required=False,
724
- )
725
- plotInitialSortingDirection.group = "General"
726
- plotMGacquisitionFreq = forms.BooleanField(
727
- label="Acquisition frequency", required=False
728
- )
729
- plotMGacquisitionFreq.group = "Acquisition protocol"
730
- plotMGaverageAGD = forms.BooleanField(
731
- label="Acquisition average AGD", required=False
732
- )
733
- plotMGaverageAGD.group = "Acquisition protocol"
734
- plotMGaverageAGDvsThickness = forms.BooleanField(
735
- label="Acquisition average AGD vs. compressed thickness", required=False
736
- )
737
- plotMGaverageAGDvsThickness.group = "Acquisition protocol"
738
- plotMGAcquisitionAGDOverTime = forms.BooleanField(
739
- label="Acquisition AGD over time", required=False
740
- )
741
- plotMGAcquisitionAGDOverTime.group = "Acquisition protocol"
742
- plotMGAGDvsThickness = forms.BooleanField(
743
- label="Acquisition AGD vs. compressed thickness", required=False
744
- )
745
- plotMGAGDvsThickness.group = "Acquisition protocol"
746
- plotMGmAsvsThickness = forms.BooleanField(
747
- label="Acquisition mAs vs. compressed thickness", required=False
748
- )
749
- plotMGmAsvsThickness.group = "Acquisition protocol"
750
- plotMGkVpvsThickness = forms.BooleanField(
751
- label="Acquisition kVp vs. compressed thickness", required=False
752
- )
753
- plotMGkVpvsThickness.group = "Acquisition protocol"
754
- plotMGStudyPerDayAndHour = forms.BooleanField(
755
- label="Study workload", required=False
756
- )
757
- plotMGStudyPerDayAndHour.group = "Study description"
758
-
759
-
760
- class MGChartOptionsFormIncStandard(MGChartOptionsForm):
761
- plotMGStandardAcquisitionFreq = forms.BooleanField(
762
- label="Standard acquisition name frequency", required=False
763
- )
764
- plotMGStandardAcquisitionFreq.group = "Standard acquisition name"
765
- plotMGStandardAverageAGD = forms.BooleanField(
766
- label="Standard acquisition name average AGD", required=False
767
- )
768
- plotMGStandardAverageAGD.group = "Standard acquisition name"
769
- plotMGStandardAverageAGDvsThickness = forms.BooleanField(
770
- label="Standard acquisition name average AGD vs. compressed thickness",
771
- required=False,
772
- )
773
- plotMGStandardAverageAGDvsThickness.group = "Standard acquisition name"
774
- plotMGStandardAcquisitionAGDOverTime = forms.BooleanField(
775
- label="Standard acquisition name AGD over time", required=False
776
- )
777
- plotMGStandardAcquisitionAGDOverTime.group = "Standard acquisition name"
778
- plotMGStandardAGDvsThickness = forms.BooleanField(
779
- label="Standard acquisition name AGD vs. compressed thickness", required=False
780
- )
781
- plotMGStandardAGDvsThickness.group = "Standard acquisition name"
782
- plotMGStandardmAsvsThickness = forms.BooleanField(
783
- label="Standard acquisition name mAs vs. compressed thickness", required=False
784
- )
785
- plotMGStandardmAsvsThickness.group = "Standard acquisition name"
786
- plotMGStandardkVpvsThickness = forms.BooleanField(
787
- label="Standard acquisition name kVp vs. compressed thickness", required=False
788
- )
789
- plotMGStandardkVpvsThickness.group = "Standard acquisition name"
790
- plotMGStandardStudyPerDayAndHour = forms.BooleanField(
791
- label="Standard study name workload", required=False
792
- )
793
- plotMGStandardStudyPerDayAndHour.group = "Standard study name"
794
-
795
-
796
- class MGChartOptionsDisplayForm(forms.Form):
797
- """Form for MG chart display options"""
798
-
799
- plotMGacquisitionFreq = forms.BooleanField(
800
- label=_("Acquisition frequency"), required=False
801
- )
802
- plotMGaverageAGD = forms.BooleanField(
803
- label=_("Acquisition average AGD"), required=False
804
- )
805
- plotMGaverageAGDvsThickness = forms.BooleanField(
806
- label=_("Acquisition average AGD vs. compressed thickness"), required=False
807
- )
808
- plotMGAcquisitionAGDOverTime = forms.BooleanField(
809
- label=_("Acquisition AGD over time"), required=False
810
- )
811
- plotMGAGDvsThickness = forms.BooleanField(
812
- label=_("Acquisition AGD vs. compressed thickness"), required=False
813
- )
814
- plotMGmAsvsThickness = forms.BooleanField(
815
- label=_("Acquisition mAs vs. compressed thickness"), required=False
816
- )
817
- plotMGkVpvsThickness = forms.BooleanField(
818
- label=_("Acquisition kVp vs. compressed thickness"), required=False
819
- )
820
- plotMGStudyPerDayAndHour = forms.BooleanField(
821
- label=_("Study workload"), required=False
822
- )
823
- plotMGOverTimePeriod = forms.ChoiceField(
824
- label=_("Time period"), choices=CommonVariables.TIME_PERIOD, required=False
825
- )
826
- plotMGInitialSortingChoice = forms.ChoiceField(
827
- label=_("Chart sorting"),
828
- choices=CommonVariables.SORTING_CHOICES,
829
- required=False,
830
- )
831
-
832
-
833
- class MGChartOptionsDisplayFormIncStandard(MGChartOptionsDisplayForm):
834
- plotMGStandardAcquisitionFreq = forms.BooleanField(
835
- label="Standard acquisition name frequency", required=False
836
- )
837
- plotMGStandardAverageAGD = forms.BooleanField(
838
- label="Standard acquisition name average AGD", required=False
839
- )
840
- plotMGStandardAverageAGDvsThickness = forms.BooleanField(
841
- label="Standard acquisition name average AGD vs. compressed thickness",
842
- required=False,
843
- )
844
- plotMGStandardAcquisitionAGDOverTime = forms.BooleanField(
845
- label="Standard acquisition name AGD over time", required=False
846
- )
847
- plotMGStandardAGDvsThickness = forms.BooleanField(
848
- label="Standard acquisition name AGD vs. compressed thickness", required=False
849
- )
850
- plotMGStandardmAsvsThickness = forms.BooleanField(
851
- label="Standard acquisition name mAs vs. compressed thickness", required=False
852
- )
853
- plotMGStandardkVpvsThickness = forms.BooleanField(
854
- label="Standard acquisition name kVp vs. compressed thickness", required=False
855
- )
856
- plotMGStandardStudyPerDayAndHour = forms.BooleanField(
857
- label="Standard study name", required=False
858
- )
859
-
860
- field_order = [
861
- "plotMGacquisitionFreq",
862
- "plotMGaverageAGD",
863
- "plotMGaverageAGDvsThickness",
864
- "plotMGAcquisitionAGDOverTime",
865
- "plotMGAGDvsThickness",
866
- "plotMGmAsvsThickness",
867
- "plotMGkVpvsThickness",
868
- "plotMGStandardAcquisitionFreq",
869
- "plotMGStandardAverageAGD",
870
- "plotMGStandardAverageAGDvsThickness",
871
- "plotMGStandardAcquisitionAGDOverTime",
872
- "plotMGStandardAGDvsThickness",
873
- "plotMGStandardmAsvsThickness",
874
- "plotMGStandardkVpvsThickness",
875
- "plotMGStudyPerDayAndHour",
876
- "plotMGStandardStudyPerDayAndHour",
877
- "plotMGOverTimePeriod",
878
- "plotMGInitialSortingChoice",
879
- ]
880
-
881
-
882
- class DXChartOptionsDisplayForm(forms.Form):
883
- """Form for DX chart display options"""
884
-
885
- plotDXAcquisitionFreq = forms.BooleanField(
886
- label=_("Acquisition frequency"), required=False
887
- )
888
- plotDXAcquisitionMeanDAP = forms.BooleanField(
889
- label=_("Acquisition DAP"), required=False
890
- )
891
- plotDXAcquisitionMeanmAs = forms.BooleanField(
892
- label=_("Acquisition mAs"), required=False
893
- )
894
- plotDXAcquisitionMeankVp = forms.BooleanField(
895
- label=_("Acquisition kVp"), required=False
896
- )
897
- plotDXAcquisitionMeanDAPOverTime = forms.BooleanField(
898
- label=_("Acquisition DAP over time"), required=False
899
- )
900
- plotDXAcquisitionMeanmAsOverTime = forms.BooleanField(
901
- label=_("Acquisition mAs over time"), required=False
902
- )
903
- plotDXAcquisitionMeankVpOverTime = forms.BooleanField(
904
- label=_("Acquisition kVp over time"), required=False
905
- )
906
- plotDXAcquisitionDAPvsMass = forms.BooleanField(
907
- label=_("Acquisition DAP vs mass"), required=False
908
- )
909
- plotDXStudyFreq = forms.BooleanField(label=_("Study frequency"), required=False)
910
- plotDXStudyMeanDAP = forms.BooleanField(label=_("Study DAP"), required=False)
911
- plotDXStudyDAPvsMass = forms.BooleanField(
912
- label=_("Study DAP vs mass"), required=False
913
- )
914
- plotDXStudyPerDayAndHour = forms.BooleanField(
915
- label=_("Study workload"), required=False
916
- )
917
- plotDXRequestFreq = forms.BooleanField(
918
- label=_("Requested procedure frequency"), required=False
919
- )
920
- plotDXRequestMeanDAP = forms.BooleanField(
921
- label=_("Requested procedure DAP"), required=False
922
- )
923
- plotDXRequestDAPvsMass = forms.BooleanField(
924
- label=_("Requested procedure DAP vs mass"), required=False
925
- )
926
- plotDXAcquisitionMeanDAPOverTimePeriod = forms.ChoiceField(
927
- label=_("Time period"), choices=CommonVariables.TIME_PERIOD, required=False
928
- )
929
- plotDXInitialSortingChoice = forms.ChoiceField(
930
- label=_("Default chart sorting"),
931
- choices=CommonVariables.SORTING_CHOICES,
932
- required=False,
933
- )
934
-
935
-
936
- class DXChartOptionsDisplayFormIncStandard(DXChartOptionsDisplayForm):
937
- plotDXStandardAcquisitionFreq = forms.BooleanField(
938
- label="Standard acquisition name frequency", required=False
939
- )
940
- plotDXStandardAcquisitionMeanDAP = forms.BooleanField(
941
- label="Standard acquisition name DAP", required=False
942
- )
943
- plotDXStandardAcquisitionMeanmAs = forms.BooleanField(
944
- label="Standard acquisition name mAs", required=False
945
- )
946
- plotDXStandardAcquisitionMeankVp = forms.BooleanField(
947
- label="Standard acquisition name kVp", required=False
948
- )
949
- plotDXStandardAcquisitionMeanDAPOverTime = forms.BooleanField(
950
- label="Standard acquisition name DAP over time", required=False
951
- )
952
- plotDXStandardAcquisitionMeanmAsOverTime = forms.BooleanField(
953
- label="Standard acquisition name mAs over time", required=False
954
- )
955
- plotDXStandardAcquisitionMeankVpOverTime = forms.BooleanField(
956
- label="Standard acquisition name kVp over time", required=False
957
- )
958
- plotDXStandardAcquisitionDAPvsMass = forms.BooleanField(
959
- label="Standard acquisition name DAP vs mass", required=False
960
- )
961
- plotDXStandardStudyFreq = forms.BooleanField(
962
- label="Standard study name frequency", required=False
963
- )
964
- plotDXStandardStudyMeanDAP = forms.BooleanField(
965
- label="Standard study name DAP", required=False
966
- )
967
- plotDXStandardStudyDAPvsMass = forms.BooleanField(
968
- label="Standard study name DAP vs mass", required=False
969
- )
970
- plotDXStandardStudyPerDayAndHour = forms.BooleanField(
971
- label="Standard study name workload", required=False
972
- )
973
-
974
- field_order = [
975
- "plotDXAcquisitionFreq",
976
- "plotDXAcquisitionMeanDAP",
977
- "plotDXAcquisitionMeanmAs",
978
- "plotDXAcquisitionMeankVp",
979
- "plotDXAcquisitionMeanDAPOverTime",
980
- "plotDXAcquisitionMeanmAsOverTime",
981
- "plotDXAcquisitionMeankVpOverTime",
982
- "plotDXAcquisitionDAPvsMass",
983
- "plotDXStandardAcquisitionFreq",
984
- "plotDXStandardAcquisitionMeanDAP",
985
- "plotDXStandardAcquisitionMeanmAs",
986
- "plotDXStandardAcquisitionMeankVp",
987
- "plotDXStandardAcquisitionMeanDAPOverTime",
988
- "plotDXStandardAcquisitionMeanmAsOverTime",
989
- "plotDXStandardAcquisitionMeankVpOverTime",
990
- "plotDXStandardAcquisitionDAPvsMass",
991
- "plotDXStudyFreq",
992
- "plotDXStudyMeanDAP",
993
- "plotDXStudyDAPvsMass",
994
- "plotDXStudyPerDayAndHour",
995
- "plotDXRequestFreq",
996
- "plotDXRequestMeanDAP",
997
- "plotDXRequestDAPvsMass",
998
- "plotDXStandardStudyFreq",
999
- "plotDXStandardStudyMeanDAP",
1000
- "plotDXStandardStudyDAPvsMass",
1001
- "plotDXStandardStudyPerDayAndHour",
1002
- "plotDXAcquisitionMeanDAPOverTimePeriod",
1003
- "plotDXInitialSortingChoice",
1004
- ]
1005
-
1006
-
1007
- class CTChartOptionsDisplayForm(forms.Form):
1008
- """Form for CT chart display options"""
1009
-
1010
- plotCTAcquisitionFreq = forms.BooleanField(
1011
- label=_("Acquisition frequency"), required=False
1012
- )
1013
- plotCTAcquisitionMeanDLP = forms.BooleanField(
1014
- label=_("Acquisition DLP"), required=False
1015
- )
1016
- plotCTAcquisitionMeanCTDI = forms.BooleanField(
1017
- label=mark_safe(_("Acquisition CTDI<sub>vol</sub>")), required=False # nosec
1018
- )
1019
- plotCTAcquisitionDLPOverTime = forms.BooleanField(
1020
- label=_("Acquisition DLP over time"), required=False
1021
- )
1022
- plotCTAcquisitionCTDIOverTime = forms.BooleanField(
1023
- label=mark_safe(_("Acquisition CTDI<sub>vol</sub> over time")), # nosec
1024
- required=False,
1025
- )
1026
- plotCTAcquisitionDLPvsMass = forms.BooleanField(
1027
- label=_("Acquisition DLP vs mass"), required=False
1028
- )
1029
- plotCTAcquisitionCTDIvsMass = forms.BooleanField(
1030
- label=_("Acquisition CTDI vs mass"), required=False
1031
- )
1032
- plotCTAcquisitionTypes = forms.MultipleChoiceField(
1033
- label=mark_safe( # nosec
1034
- _(
1035
- "Acquisition types to include<br/>in acquisition-level chart<br/>calculations"
1036
- )
1037
- ),
1038
- choices=CommonVariables.CT_ACQUISITION_TYPES,
1039
- required=False,
1040
- widget=forms.CheckboxSelectMultiple(attrs={"class": "CheckboxSelectMultiple"}),
1041
- )
1042
- plotCTStudyFreq = forms.BooleanField(label=_("Study frequency"), required=False)
1043
- plotCTStudyMeanDLP = forms.BooleanField(label=_("Study DLP"), required=False)
1044
- plotCTStudyMeanCTDI = forms.BooleanField(
1045
- label=mark_safe(_("Study CTDI<sub>vol</sub>")), required=False # nosec
1046
- )
1047
- plotCTStudyNumEvents = forms.BooleanField(label=_("Study events"), required=False)
1048
- plotCTStudyMeanDLPOverTime = forms.BooleanField(
1049
- label=_("Study DLP over time"), required=False
1050
- )
1051
- plotCTStudyPerDayAndHour = forms.BooleanField(
1052
- label=_("Study workload"), required=False
1053
- )
1054
- plotCTRequestFreq = forms.BooleanField(
1055
- label=_("Requested procedure frequency"), required=False
1056
- )
1057
- plotCTRequestMeanDLP = forms.BooleanField(
1058
- label=_("Requested procedure DLP"), required=False
1059
- )
1060
- plotCTRequestNumEvents = forms.BooleanField(
1061
- label=_("Requested procedure events"), required=False
1062
- )
1063
- plotCTRequestDLPOverTime = forms.BooleanField(
1064
- label=_("Requested procedure DLP over time"), required=False
1065
- )
1066
- plotCTOverTimePeriod = forms.ChoiceField(
1067
- label=_("Time period"), choices=CommonVariables.TIME_PERIOD, required=False
1068
- )
1069
- plotCTInitialSortingChoice = forms.ChoiceField(
1070
- label=_("Chart sorting"),
1071
- choices=CommonVariables.SORTING_CHOICES,
1072
- required=False,
1073
- )
1074
-
1075
-
1076
- class CTChartOptionsDisplayFormIncStandard(CTChartOptionsDisplayForm):
1077
- plotCTStandardAcquisitionFreq = forms.BooleanField(
1078
- label="Standard acquisition name frequency", required=False
1079
- )
1080
- plotCTStandardAcquisitionMeanDLP = forms.BooleanField(
1081
- label="Standard acquisition DLP", required=False
1082
- )
1083
- plotCTStandardAcquisitionMeanCTDI = forms.BooleanField(
1084
- label=mark_safe("Standard acquisition CTDI<sub>vol</sub>"), # nosec
1085
- required=False,
1086
- )
1087
- plotCTStandardAcquisitionDLPOverTime = forms.BooleanField(
1088
- label="Standard acquisition name DLP over time", required=False
1089
- )
1090
- plotCTStandardAcquisitionCTDIOverTime = forms.BooleanField(
1091
- label=mark_safe( # nosec
1092
- "Standard acquisition name CTDI<sub>vol</sub> over time"
1093
- ),
1094
- required=False,
1095
- )
1096
- plotCTStandardAcquisitionCTDIvsMass = forms.BooleanField(
1097
- label=mark_safe( # nosec
1098
- "Standard acquisition name CTDI<sub>vol</sub> vs mass"
1099
- ),
1100
- required=False,
1101
- )
1102
- plotCTStandardAcquisitionDLPvsMass = forms.BooleanField(
1103
- label="Standard acquisition name DLP vs mass", required=False
1104
- )
1105
-
1106
- plotCTStandardStudyMeanDLP = forms.BooleanField(
1107
- label="Standard study DLP", required=False
1108
- )
1109
- plotCTStandardStudyNumEvents = forms.BooleanField(
1110
- label="Standard study events", required=False
1111
- )
1112
- plotCTStandardStudyFreq = forms.BooleanField(
1113
- label="Standard study frequency", required=False
1114
- )
1115
- plotCTStandardStudyMeanDLPOverTime = forms.BooleanField(
1116
- label="Standard study DLP over time", required=False
1117
- )
1118
- plotCTStandardStudyPerDayAndHour = forms.BooleanField(
1119
- label="Standard study workload", required=False
1120
- )
1121
-
1122
- field_order = [
1123
- "plotCTAcquisitionFreq",
1124
- "plotCTAcquisitionMeanDLP",
1125
- "plotCTAcquisitionMeanCTDI",
1126
- "plotCTAcquisitionDLPOverTime",
1127
- "plotCTAcquisitionCTDIOverTime",
1128
- "plotCTAcquisitionDLPvsMass",
1129
- "plotCTAcquisitionCTDIvsMass",
1130
- "plotCTAcquisitionTypes",
1131
- "plotCTStandardAcquisitionFreq",
1132
- "plotCTStandardAcquisitionMeanDLP",
1133
- "plotCTStandardAcquisitionMeanCTDI",
1134
- "plotCTStandardAcquisitionDLPOverTime",
1135
- "plotCTStandardAcquisitionCTDIOverTime",
1136
- "plotCTStandardAcquisitionDLPvsMass",
1137
- "plotCTStandardAcquisitionCTDIvsMass",
1138
- "plotCTStudyFreq",
1139
- "plotCTStudyMeanDLP",
1140
- "plotCTStudyMeanCTDI",
1141
- "plotCTStudyNumEvents",
1142
- "plotCTStudyMeanDLPOverTime",
1143
- "plotCTStudyPerDayAndHour",
1144
- "plotCTRequestFreq",
1145
- "plotCTRequestMeanDLP",
1146
- "plotCTRequestNumEvents",
1147
- "plotCTRequestDLPOverTime",
1148
- "plotCTStandardStudyFreq",
1149
- "plotCTStandardStudyMeanDLP",
1150
- "plotCTStandardStudyNumEvents",
1151
- "plotCTStandardStudyMeanDLPOverTime",
1152
- "plotCTStandardStudyPerDayAndHour",
1153
- "plotCTOverTimePeriod",
1154
- "plotCTInitialSortingChoice",
1155
- ]
1156
-
1157
-
1158
- class GeneralChartOptionsDisplayForm(forms.Form):
1159
- """Form for general chart display options"""
1160
-
1161
- plotCharts = forms.BooleanField(label=_("Plot charts?"), required=False)
1162
- plotAverageChoice = forms.MultipleChoiceField(
1163
- label=_("Average plots"),
1164
- choices=CommonVariables.AVERAGES,
1165
- required=False,
1166
- widget=forms.CheckboxSelectMultiple(attrs={"class": "CheckboxSelectMultiple"}),
1167
- )
1168
- plotInitialSortingDirection = forms.ChoiceField(
1169
- label=_("Sorting direction"),
1170
- choices=CommonVariables.SORTING_DIRECTION,
1171
- required=False,
1172
- )
1173
- plotSeriesPerSystem = forms.BooleanField(
1174
- label=_("Plot a series per system"), required=False
1175
- )
1176
- plotHistograms = forms.BooleanField(
1177
- label=_("Calculate histogram data"), required=False
1178
- )
1179
- plotHistogramBins = forms.IntegerField(
1180
- label=_("Number of histogram bins"), min_value=2, max_value=40, required=False
1181
- )
1182
- plotHistogramGlobalBins = forms.BooleanField(
1183
- label=_("Fixed histogram bins across subplots"), required=False
1184
- )
1185
- plotCaseInsensitiveCategories = forms.BooleanField(
1186
- label=_("Case-insensitive categories"), required=False
1187
- )
1188
- plotRemoveCategoryWhitespacePadding = forms.BooleanField(
1189
- label=_("Remove category whitespace padding"), required=False
1190
- )
1191
- plotLabelCharWrap = forms.IntegerField(
1192
- label=_("Chart label character wrap length"),
1193
- min_value=10,
1194
- max_value=500,
1195
- required=False,
1196
- )
1197
- plotGrouping = forms.ChoiceField(
1198
- label=_("Chart grouping"),
1199
- choices=CommonVariables.CHART_GROUPING,
1200
- required=False,
1201
- )
1202
- plotThemeChoice = forms.ChoiceField(
1203
- label=_("Chart theme"), choices=CommonVariables.CHART_THEMES, required=False
1204
- )
1205
- plotColourMapChoice = forms.ChoiceField(
1206
- label=_("Colour map choice"),
1207
- choices=CommonVariables.CHART_COLOUR_MAPS,
1208
- required=False,
1209
- widget=forms.RadioSelect(attrs={"id": "value"}),
1210
- )
1211
- plotFacetColWrapVal = forms.IntegerField(
1212
- label=_("Number of sub-charts per row"),
1213
- min_value=1,
1214
- max_value=10,
1215
- required=False,
1216
- )
1217
-
1218
-
1219
- class UpdateDisplayNamesForm(forms.Form):
1220
- display_names = forms.CharField()
1221
-
1222
-
1223
- class RFHighDoseFluoroAlertsForm(forms.ModelForm):
1224
- """Form for displaying and changing fluoroscopy high dose alert settings"""
1225
-
1226
- def __init__(self, *args, **kwargs):
1227
- from crispy_forms.layout import Button
1228
-
1229
- super(RFHighDoseFluoroAlertsForm, self).__init__(*args, **kwargs)
1230
- self.helper = FormHelper(self)
1231
- self.helper.form_class = "form-horizontal"
1232
-
1233
- # If HighDoseMetricAlertSettings.changed_accum_dose_delta_weeks is True then the summed DAP and dose at RP
1234
- # values have not yet been recalculated - display the recalculate button on the form.
1235
- if self.instance.changed_accum_dose_delta_weeks:
1236
- self.helper.add_input(
1237
- Button(
1238
- "recalc_all_summed_data",
1239
- "Recalculate all summed data",
1240
- css_class="btn btn-warning",
1241
- )
1242
- )
1243
-
1244
- # If there is nothing in self.data and accum_dose_delta_weeks is in self.changed_data then the user must have
1245
- # changed the accum_dose_delta_weeks value: set the changed_accum_dose_delta_weeks flag to True. This updates
1246
- # the HighDoseMetricAlertSettings.changed_accum_dose_delta_weeks to True.
1247
- if len(self.data):
1248
- if self.has_changed():
1249
- if "accum_dose_delta_weeks" in self.changed_data:
1250
- self.instance.changed_accum_dose_delta_weeks = True
1251
- self.save()
1252
- self.helper.layout = Layout(
1253
- Div(
1254
- "alert_total_dap_rf",
1255
- "alert_total_rp_dose_rf",
1256
- "alert_skindose",
1257
- "accum_dose_delta_weeks",
1258
- "show_accum_dose_over_delta_weeks",
1259
- "calc_accum_dose_over_delta_weeks_on_import",
1260
- "send_high_dose_metric_alert_emails_ref",
1261
- "send_high_dose_metric_alert_emails_skin",
1262
- ),
1263
- FormActions(Submit("submit", "Submit")),
1264
- )
1265
-
1266
- class Meta(object):
1267
- model = HighDoseMetricAlertSettings
1268
- fields = [
1269
- "alert_total_dap_rf",
1270
- "alert_total_rp_dose_rf",
1271
- "alert_skindose",
1272
- "accum_dose_delta_weeks",
1273
- "show_accum_dose_over_delta_weeks",
1274
- "calc_accum_dose_over_delta_weeks_on_import",
1275
- "send_high_dose_metric_alert_emails_ref",
1276
- "send_high_dose_metric_alert_emails_skin",
1277
- ]
1278
-
1279
-
1280
- class HomepageOptionsForm(forms.Form):
1281
- """Form for displaying and changing the home page options"""
1282
-
1283
- dayDeltaA = forms.IntegerField(
1284
- label=_("Primary time period to sum studies (days)"), required=False
1285
- )
1286
- dayDeltaB = forms.IntegerField(
1287
- label=_("Secondary time period to sum studies (days)"), required=False
1288
- )
1289
- enable_workload_stats = forms.BooleanField(
1290
- label=_("Enable calculation and display of workload stats on home page?"),
1291
- required=False,
1292
- )
1293
-
1294
-
1295
- class MergeOnDeviceObserverUIDForm(forms.Form):
1296
- """Form for displaying and changing the option for merging on Device Observer UID"""
1297
-
1298
- match_on_device_observer_uid = forms.BooleanField(
1299
- label=_(
1300
- "Set Display Name and Modality type if Device Observer UID is matching"
1301
- ),
1302
- required=False,
1303
- )
1304
-
1305
-
1306
- class DicomQueryForm(forms.Form):
1307
- """Form for launching DICOM Query"""
1308
-
1309
- from datetime import date
1310
-
1311
- MODALITIES = (
1312
- ("CT", _("CT")),
1313
- ("FL", _("Fluoroscopy (XA and RF)")),
1314
- ("DX", _("DX, including CR")),
1315
- ("MG", _("Mammography")),
1316
- ("NM", _("Nuclear Medicine")),
1317
- )
1318
-
1319
- remote_host_field = forms.ChoiceField(
1320
- choices=[], widget=forms.Select(attrs={"class": "form-control"})
1321
- )
1322
- store_scp_field = forms.ChoiceField(
1323
- choices=[], widget=forms.Select(attrs={"class": "form-control"})
1324
- )
1325
- date_from_field = forms.DateField(
1326
- label=_("Date from"),
1327
- widget=forms.DateInput(attrs={"class": "form-control datepicker"}),
1328
- required=False,
1329
- initial=date.today().isoformat(),
1330
- help_text=_("Format yyyy-mm-dd, restrict as much as possible for best results"),
1331
- )
1332
- date_until_field = forms.DateField(
1333
- label=_("Date until"),
1334
- widget=forms.DateInput(attrs={"class": "form-control datepicker"}),
1335
- required=False,
1336
- help_text=_("Format yyyy-mm-dd, restrict as much as possible for best results"),
1337
- )
1338
- modality_field = forms.MultipleChoiceField(
1339
- choices=MODALITIES,
1340
- widget=forms.CheckboxSelectMultiple(attrs={"checked": ""}),
1341
- required=False,
1342
- help_text=(
1343
- _(
1344
- "At least one modality must be ticked - if SR only is ticked (Advanced) these "
1345
- "modalities will be ignored"
1346
- )
1347
- ),
1348
- )
1349
- inc_sr_field = forms.BooleanField(
1350
- label=_("Include SR only studies?"),
1351
- required=False,
1352
- initial=False,
1353
- help_text=_(
1354
- "Only use with stores containing only RDSRs, with no accompanying images"
1355
- ),
1356
- )
1357
- duplicates_field = forms.BooleanField(
1358
- label=_("Ignore studies already in the database?"),
1359
- required=False,
1360
- initial=True,
1361
- help_text=_(
1362
- "Objects that have already been processed won't be imported, "
1363
- "so there isn't any point getting them!"
1364
- ),
1365
- )
1366
- desc_exclude_field = forms.CharField(
1367
- required=False,
1368
- label=_("Exclude studies with these terms in the study description:"),
1369
- help_text=_("Comma separated list of terms"),
1370
- )
1371
- desc_include_field = forms.CharField(
1372
- required=False,
1373
- label=_("Only keep studies with these terms in the study description:"),
1374
- help_text=_("Comma separated list of terms"),
1375
- )
1376
- stationname_exclude_field = forms.CharField(
1377
- required=False,
1378
- label=_("Exclude studies or series with these terms in the station name:"),
1379
- help_text=_(
1380
- "Comma separated list of terms, tested at series level — see Advanced"
1381
- ),
1382
- )
1383
- stationname_include_field = forms.CharField(
1384
- required=False,
1385
- label=_("Only keep studies or series with these terms in the station name:"),
1386
- help_text=_(
1387
- "Comma separated list of terms, tested at series level — see Advanced"
1388
- ),
1389
- )
1390
- get_toshiba_images_field = forms.BooleanField(
1391
- label=_("Attempt to get Toshiba dose images"),
1392
- required=False,
1393
- help_text=_(
1394
- "Only applicable if using Toshiba RDSR generator extension, see docs"
1395
- ),
1396
- )
1397
- get_empty_sr_field = forms.BooleanField(
1398
- label=_("Get SR series that return nothing at image level query"),
1399
- help_text=_("Only use if suggested in qrscu log, see docs"),
1400
- required=False,
1401
- )
1402
- stationname_study_level_field = forms.BooleanField(
1403
- label=_("Check station name include/exclude at study level"),
1404
- help_text=_("Default from v1.0 is to check at series level only"),
1405
- required=False,
1406
- )
1407
-
1408
- def __init__(self, *args, **kwargs):
1409
- super(DicomQueryForm, self).__init__(*args, **kwargs)
1410
-
1411
- self.fields["remote_host_field"].choices = [
1412
- (x.pk, x.name) for x in DicomRemoteQR.objects.all()
1413
- ]
1414
- self.fields["store_scp_field"].choices = [
1415
- (x.pk, x.name) for x in DicomStoreSCP.objects.all()
1416
- ]
1417
- self.helper = FormHelper(self)
1418
- self.helper.form_id = "post-form"
1419
- self.helper.form_method = "post"
1420
- self.helper.form_action = "queryprocess"
1421
- self.helper.add_input(Submit("submit", "Submit"))
1422
- self.helper.layout = Layout(
1423
- Div(
1424
- Div(
1425
- Div("remote_host_field", css_class="col-md-6"),
1426
- Div("store_scp_field", css_class="col-md-6"),
1427
- ),
1428
- InlineCheckboxes("modality_field"),
1429
- Div(
1430
- Div("date_from_field", css_class="col-md-6"),
1431
- Div("date_until_field", css_class="col-md-6"),
1432
- ),
1433
- "desc_exclude_field",
1434
- "desc_include_field",
1435
- "stationname_exclude_field",
1436
- "stationname_include_field",
1437
- Accordion(
1438
- AccordionGroup(
1439
- "Advanced",
1440
- "get_toshiba_images_field",
1441
- "duplicates_field",
1442
- "inc_sr_field",
1443
- "get_empty_sr_field",
1444
- "stationname_study_level_field",
1445
- active=False,
1446
- )
1447
- ),
1448
- )
1449
- )
1450
-
1451
- def clean(self):
1452
- """
1453
- Validate the form data to clear modality selections if sr_only is selected.
1454
- :return: Form with modalities _or_ sr_only selected
1455
- """
1456
- qr_logger = logging.getLogger("remapp.netdicom.qrscu")
1457
-
1458
- cleaned_data = super(DicomQueryForm, self).clean()
1459
- mods = cleaned_data.get("modality_field")
1460
- inc_sr = cleaned_data.get("inc_sr_field")
1461
- qr_logger.debug("Form mods are {0}, inc_sr is {1}".format(mods, inc_sr))
1462
- qr_logger.debug("All form modes are {0}".format(cleaned_data))
1463
- if inc_sr:
1464
- self.cleaned_data["modality_field"] = None
1465
- elif not mods:
1466
- raise forms.ValidationError(
1467
- "You must select at least one modality (or Advanced SR Only)"
1468
- )
1469
- return cleaned_data
1470
-
1471
-
1472
- class DicomDeleteSettingsForm(forms.ModelForm):
1473
- """Form for configuring whether DICOM objects are stored or deleted once processed"""
1474
-
1475
- def __init__(self, *args, **kwargs):
1476
- super(DicomDeleteSettingsForm, self).__init__(*args, **kwargs)
1477
- self.helper = FormHelper(self)
1478
- self.helper.form_class = "form-horizontal"
1479
- self.helper.label_class = "col-lg-2"
1480
- self.helper.field_class = "col-lg-8"
1481
- self.helper.layout = Layout(
1482
- Div(
1483
- HTML(
1484
- """
1485
- <h4>Do you want objects that we can't do anything with to be deleted?</h4>
1486
- """
1487
- ),
1488
- "del_no_match",
1489
- HTML(
1490
- """
1491
- <h4>The remaining choices are for DICOM objects we have processed and attempted to import to the
1492
- database:</h4>
1493
- """
1494
- ),
1495
- "del_rdsr",
1496
- "del_mg_im",
1497
- "del_dx_im",
1498
- "del_ct_phil",
1499
- "del_nm_im",
1500
- ),
1501
- FormActions(Submit("submit", "Submit")),
1502
- Div(
1503
- HTML(
1504
- """
1505
- <div class="col-lg-4 col-lg-offset-2">
1506
- <a href='"""
1507
- + reverse("dicom_summary")
1508
- + """#delete' role="button" class="btn btn-default">
1509
- Cancel and return to the DICOM configuration and DICOM object delete summary page
1510
- </a>
1511
- </div>
1512
- """
1513
- )
1514
- ),
1515
- )
1516
-
1517
- class Meta(object):
1518
- model = DicomDeleteSettings
1519
- fields = [
1520
- "del_no_match",
1521
- "del_rdsr",
1522
- "del_mg_im",
1523
- "del_dx_im",
1524
- "del_ct_phil",
1525
- "del_nm_im",
1526
- ]
1527
-
1528
-
1529
- class DicomQRForm(forms.ModelForm):
1530
- """Form for configuring remote Query Retrieve nodes"""
1531
-
1532
- def __init__(self, *args, **kwargs):
1533
- super(DicomQRForm, self).__init__(*args, **kwargs)
1534
- self.helper = FormHelper(self)
1535
- self.helper.form_class = "form-horizontal"
1536
- self.helper.label_class = "col-md-8"
1537
- self.helper.field_class = "col-md-4"
1538
- self.helper.layout = Layout(
1539
- Div("name", "aetitle", "callingaet", "port", "ip", "hostname"),
1540
- Accordion(
1541
- AccordionGroup(
1542
- "Non-standard configuration options",
1543
- Div(
1544
- HTML(
1545
- """
1546
- <p>
1547
- Some PACS systems (like Impax 6.6) need modality at study level for correct filtering.
1548
- Others will return no results if modality is included at study level. See
1549
- <a href="https://docs.openrem.org/en/{{ admin.docsversion }}/netdicom-qr-config.html"
1550
- target="_blank" data-toggle="tooltip"
1551
- title="DICOM query-retrieve node config documentation - opens in a new tab">
1552
- DICOM query-retrieve node config documentation
1553
- </a>
1554
- </p>
1555
- """
1556
- )
1557
- ),
1558
- PrependedText(
1559
- "use_modality_tag", ""
1560
- ), # Trick to force label to join the other labels,
1561
- # otherwise sits to right
1562
- active=False,
1563
- )
1564
- ),
1565
- FormActions(Submit("submit", "Submit")),
1566
- Div(
1567
- HTML(
1568
- """
1569
- <div class="col-lg-4 col-lg-offset-4">
1570
- <a href='"""
1571
- + reverse("dicom_summary")
1572
- + """' role="button" class="btn btn-default">
1573
- Cancel and return to DICOM configuration summary page
1574
- </a>
1575
- </div>
1576
- """
1577
- )
1578
- ),
1579
- )
1580
-
1581
- class Meta(object):
1582
- model = DicomRemoteQR
1583
- fields = [
1584
- "name",
1585
- "aetitle",
1586
- "callingaet",
1587
- "port",
1588
- "ip",
1589
- "hostname",
1590
- "use_modality_tag",
1591
- ]
1592
-
1593
-
1594
- class DicomStoreForm(forms.ModelForm):
1595
- """Form for configuring local Store nodes"""
1596
-
1597
- def __init__(self, *args, **kwargs):
1598
- super(DicomStoreForm, self).__init__(*args, **kwargs)
1599
- self.helper = FormHelper(self)
1600
- self.helper.form_class = "form-horizontal"
1601
- self.helper.label_class = "col-md-8"
1602
- self.helper.field_class = "col-md-4"
1603
- if not settings.DOCKER_INSTALL:
1604
- self.helper.layout = Layout(
1605
- Div("name", "aetitle", "peer", "port"),
1606
- FormActions(Submit("submit", "Submit")),
1607
- Div(
1608
- HTML(
1609
- """
1610
- <div class="col-lg-4 col-lg-offset-4">
1611
- <a href='"""
1612
- + reverse("dicom_summary")
1613
- + """' role="button" class="btn btn-default">
1614
- Cancel and return to DICOM configuration summary page
1615
- </a>
1616
- </div>
1617
- """
1618
- )
1619
- ),
1620
- )
1621
- else:
1622
- self.helper.layout = Layout(
1623
- Div("name", "aetitle", "peer", "port"),
1624
- FormActions(Submit("submit", "Submit")),
1625
- Div(
1626
- HTML(
1627
- """
1628
- <div class="col-lg-4 col-lg-offset-4">
1629
- <a href='"""
1630
- + reverse("dicom_summary")
1631
- + """' role="button" class="btn btn-default">
1632
- Cancel and return to DICOM configuration summary page
1633
- </a>
1634
- </div>
1635
- """
1636
- )
1637
- ),
1638
- )
1639
-
1640
- class Meta(object):
1641
- model = DicomStoreSCP
1642
- fields = ["name", "aetitle", "peer", "port"]
1643
- labels = {
1644
- "peer": "Peer: Set this to localhost",
1645
- "port": "Port: port 104 is standard for DICOM but ports higher than 1024 require fewer admin rights",
1646
- }
1647
- if settings.DOCKER_INSTALL:
1648
- labels["peer"] = "Docker container name: initial default is orthanc_1"
1649
- labels[
1650
- "port"
1651
- ] = "Port: set to the same as the DICOM_PORT setting in docker-compose.yml"
1652
-
1653
-
1654
- class StandardNameFormBase(forms.ModelForm):
1655
- """For configuring standard names for study description, requested procedure, procedure and acquisition name."""
1656
-
1657
- class Meta(object):
1658
- model = StandardNames
1659
- fields = [
1660
- "standard_name",
1661
- "modality",
1662
- "study_description",
1663
- "requested_procedure_code_meaning",
1664
- "procedure_code_meaning",
1665
- "acquisition_protocol",
1666
- ]
1667
- widgets = {
1668
- "standard_name": forms.TextInput,
1669
- "modality": forms.HiddenInput,
1670
- }
1671
-
1672
- def clean_study_description(self):
1673
- if self.cleaned_data["study_description"] == "":
1674
- return None
1675
- else:
1676
- return self.cleaned_data["study_description"]
1677
-
1678
- def clean_requested_procedure_code_meaning(self):
1679
- if self.cleaned_data["requested_procedure_code_meaning"] == "":
1680
- return None
1681
- else:
1682
- return self.cleaned_data["requested_procedure_code_meaning"]
1683
-
1684
- def clean_procedure_code_meaning(self):
1685
- if self.cleaned_data["procedure_code_meaning"] == "":
1686
- return None
1687
- else:
1688
- return self.cleaned_data["procedure_code_meaning"]
1689
-
1690
- def clean_acquisition_protocol(self):
1691
- if self.cleaned_data["acquisition_protocol"] == "":
1692
- return None
1693
- else:
1694
- return self.cleaned_data["acquisition_protocol"]
1695
-
1696
-
1697
- class StandardNameFormCT(StandardNameFormBase):
1698
- """Form for configuring standard names for study description, requested procedure, procedure and acquisition name"""
1699
-
1700
- def __init__(self, *args, **kwargs):
1701
- super(StandardNameFormCT, self).__init__(*args, **kwargs)
1702
- self.fields["modality"].initial = "CT"
1703
-
1704
- all_studies = GeneralStudyModuleAttr.objects.filter(modality_type__iexact="CT")
1705
-
1706
- field_names = [
1707
- ("study_description", "Study description"),
1708
- ("requested_procedure_code_meaning", "Requested procedure name"),
1709
- ("procedure_code_meaning", "Procedure name"),
1710
- ]
1711
-
1712
- for field_name, label_name in field_names:
1713
- # Exclude items already in the CT standard names entries except for the current value of the field
1714
- items_to_exclude = (
1715
- StandardNames.objects.all()
1716
- .filter(modality="CT")
1717
- .values(field_name)
1718
- .exclude(**{field_name: None})
1719
- )
1720
- if "standard_name" in self.initial:
1721
- items_to_exclude = items_to_exclude.exclude(
1722
- standard_name=self.initial["standard_name"]
1723
- )
1724
-
1725
- query = (
1726
- all_studies.values_list(field_name, flat=True)
1727
- .exclude(**{field_name + "__in": items_to_exclude})
1728
- .distinct()
1729
- .order_by(field_name)
1730
- )
1731
- query_choices = [("", "None")] + [(item, item) for item in query]
1732
-
1733
- initial_choices = (
1734
- StandardNames.objects.all()
1735
- .filter(modality="CT")
1736
- .exclude(**{field_name: None})
1737
- .order_by(field_name)
1738
- )
1739
- if "standard_name" in self.initial:
1740
- initial_choices = initial_choices.filter(
1741
- standard_name=self.initial["standard_name"]
1742
- )
1743
-
1744
- self.initial[field_name] = list(
1745
- initial_choices.values_list(field_name, flat=True)
1746
- )
1747
-
1748
- self.fields[field_name] = forms.MultipleChoiceField(
1749
- choices=query_choices,
1750
- required=False,
1751
- widget=FilteredSelectMultiple(
1752
- label_name.lower() + "s", is_stacked=False
1753
- ),
1754
- )
1755
-
1756
- field_name, label_name = ("acquisition_protocol", "Acquisition protocol name")
1757
- items_to_exclude = (
1758
- StandardNames.objects.all().values(field_name).exclude(**{field_name: None})
1759
- )
1760
- if "standard_name" in self.initial:
1761
- items_to_exclude = items_to_exclude.exclude(
1762
- standard_name=self.initial["standard_name"]
1763
- )
1764
- query = (
1765
- CtIrradiationEventData.objects.values_list(field_name, flat=True)
1766
- .exclude(**{field_name + "__in": items_to_exclude})
1767
- .distinct()
1768
- .order_by(field_name)
1769
- )
1770
- query_choices = [("", "None")] + [(item, item) for item in query]
1771
-
1772
- initial_choices = (
1773
- StandardNames.objects.all()
1774
- .filter(modality="CT")
1775
- .exclude(**{field_name: None})
1776
- .order_by(field_name)
1777
- )
1778
- if "standard_name" in self.initial:
1779
- initial_choices = initial_choices.filter(
1780
- standard_name=self.initial["standard_name"]
1781
- )
1782
-
1783
- self.initial[field_name] = list(
1784
- initial_choices.values_list(field_name, flat=True)
1785
- )
1786
-
1787
- self.fields[field_name] = forms.MultipleChoiceField(
1788
- choices=query_choices,
1789
- required=False,
1790
- widget=FilteredSelectMultiple(label_name.lower() + "s", is_stacked=False),
1791
- )
1792
-
1793
- class Media:
1794
- css = {
1795
- "all": (
1796
- os.path.join(settings.BASE_DIR, "/static/admin/css/widgets.css"),
1797
- ),
1798
- }
1799
- js = ("/admin/jsi18n",)
1800
-
1801
-
1802
- class StandardNameFormDX(StandardNameFormBase):
1803
- """Form for configuring standard names for study description, requested procedure, procedure and acquisition name"""
1804
-
1805
- def __init__(self, *args, **kwargs):
1806
- super(StandardNameFormDX, self).__init__(*args, **kwargs)
1807
- self.fields["modality"].initial = "DX"
1808
-
1809
- all_studies = GeneralStudyModuleAttr.objects.filter(
1810
- Q(modality_type__iexact="DX")
1811
- | Q(modality_type__iexact="CR")
1812
- | Q(modality_type__iexact="PX")
1813
- )
1814
-
1815
- field_names = [
1816
- ("study_description", "Study description"),
1817
- ("requested_procedure_code_meaning", "Requested procedure name"),
1818
- ("procedure_code_meaning", "Procedure name"),
1819
- ]
1820
-
1821
- for field_name, label_name in field_names:
1822
- # Exclude items already in the DX standard names entries except for the current value of the field
1823
- items_to_exclude = (
1824
- StandardNames.objects.all()
1825
- .filter(modality="DX")
1826
- .values(field_name)
1827
- .exclude(**{field_name: None})
1828
- )
1829
- if "standard_name" in self.initial:
1830
- items_to_exclude = items_to_exclude.exclude(
1831
- standard_name=self.initial["standard_name"]
1832
- )
1833
-
1834
- query = (
1835
- all_studies.values_list(field_name, flat=True)
1836
- .exclude(**{field_name + "__in": items_to_exclude})
1837
- .distinct()
1838
- .order_by(field_name)
1839
- )
1840
- query_choices = [("", "None")] + [(item, item) for item in query]
1841
-
1842
- initial_choices = (
1843
- StandardNames.objects.all()
1844
- .filter(modality="DX")
1845
- .exclude(**{field_name: None})
1846
- .order_by(field_name)
1847
- )
1848
- if "standard_name" in self.initial:
1849
- initial_choices = initial_choices.filter(
1850
- standard_name=self.initial["standard_name"]
1851
- )
1852
-
1853
- self.initial[field_name] = list(
1854
- initial_choices.values_list(field_name, flat=True)
1855
- )
1856
-
1857
- self.fields[field_name] = forms.MultipleChoiceField(
1858
- choices=query_choices,
1859
- required=False,
1860
- widget=FilteredSelectMultiple(
1861
- label_name.lower() + "s", is_stacked=False
1862
- ),
1863
- )
1864
-
1865
- q = ["DX", "CR", "PX"]
1866
- q_criteria = reduce(
1867
- operator.or_,
1868
- (
1869
- Q(
1870
- projection_xray_radiation_dose__general_study_module_attributes__modality_type__icontains=item
1871
- )
1872
- for item in q
1873
- ),
1874
- )
1875
- field_name, label_name = ("acquisition_protocol", "Acquisition protocol name")
1876
- items_to_exclude = (
1877
- StandardNames.objects.all().values(field_name).exclude(**{field_name: None})
1878
- )
1879
- if "standard_name" in self.initial:
1880
- items_to_exclude = items_to_exclude.exclude(
1881
- standard_name=self.initial["standard_name"]
1882
- )
1883
- query = (
1884
- IrradEventXRayData.objects.filter(q_criteria)
1885
- .values_list(field_name, flat=True)
1886
- .exclude(**{field_name + "__in": items_to_exclude})
1887
- .distinct()
1888
- .order_by(field_name)
1889
- )
1890
- query_choices = [("", "None")] + [(item, item) for item in query]
1891
-
1892
- initial_choices = (
1893
- StandardNames.objects.all()
1894
- .filter(modality="DX")
1895
- .exclude(**{field_name: None})
1896
- .order_by(field_name)
1897
- )
1898
- if "standard_name" in self.initial:
1899
- initial_choices = initial_choices.filter(
1900
- standard_name=self.initial["standard_name"]
1901
- )
1902
-
1903
- self.initial[field_name] = list(
1904
- initial_choices.values_list(field_name, flat=True)
1905
- )
1906
-
1907
- self.fields[field_name] = forms.MultipleChoiceField(
1908
- choices=query_choices,
1909
- required=False,
1910
- widget=FilteredSelectMultiple(label_name.lower() + "s", is_stacked=False),
1911
- )
1912
-
1913
- class Media:
1914
- css = {
1915
- "all": (
1916
- os.path.join(settings.BASE_DIR, "/static/admin/css/widgets.css"),
1917
- ),
1918
- }
1919
- js = ("/admin/jsi18n",)
1920
-
1921
-
1922
- class StandardNameFormMG(StandardNameFormBase):
1923
- """Form for configuring standard names for study description, requested procedure, procedure and acquisition name"""
1924
-
1925
- def __init__(self, *args, **kwargs):
1926
- super(StandardNameFormMG, self).__init__(*args, **kwargs)
1927
- self.fields["modality"].initial = "MG"
1928
-
1929
- all_studies = GeneralStudyModuleAttr.objects.filter(modality_type__iexact="MG")
1930
-
1931
- field_names = [
1932
- ("study_description", "Study description"),
1933
- ("requested_procedure_code_meaning", "Requested procedure name"),
1934
- ("procedure_code_meaning", "Procedure name"),
1935
- ]
1936
-
1937
- for field_name, label_name in field_names:
1938
- # Exclude items already in the MG standard names entries except for the current value of the field
1939
- items_to_exclude = (
1940
- StandardNames.objects.all()
1941
- .filter(modality="MG")
1942
- .values(field_name)
1943
- .exclude(**{field_name: None})
1944
- )
1945
- if "standard_name" in self.initial:
1946
- items_to_exclude = items_to_exclude.exclude(
1947
- standard_name=self.initial["standard_name"]
1948
- )
1949
-
1950
- query = (
1951
- all_studies.values_list(field_name, flat=True)
1952
- .exclude(**{field_name + "__in": items_to_exclude})
1953
- .distinct()
1954
- .order_by(field_name)
1955
- )
1956
- query_choices = [("", "None")] + [(item, item) for item in query]
1957
-
1958
- initial_choices = (
1959
- StandardNames.objects.all()
1960
- .filter(modality="MG")
1961
- .exclude(**{field_name: None})
1962
- .order_by(field_name)
1963
- )
1964
- if "standard_name" in self.initial:
1965
- initial_choices = initial_choices.filter(
1966
- standard_name=self.initial["standard_name"]
1967
- )
1968
-
1969
- self.initial[field_name] = list(
1970
- initial_choices.values_list(field_name, flat=True)
1971
- )
1972
-
1973
- self.fields[field_name] = forms.MultipleChoiceField(
1974
- choices=query_choices,
1975
- required=False,
1976
- widget=FilteredSelectMultiple(
1977
- label_name.lower() + "s", is_stacked=False
1978
- ),
1979
- )
1980
-
1981
- q = ["MG"]
1982
- q_criteria = reduce(
1983
- operator.or_,
1984
- (
1985
- Q(
1986
- projection_xray_radiation_dose__general_study_module_attributes__modality_type__icontains=item
1987
- )
1988
- for item in q
1989
- ),
1990
- )
1991
- field_name, label_name = ("acquisition_protocol", "Acquisition protocol name")
1992
- items_to_exclude = (
1993
- StandardNames.objects.all().values(field_name).exclude(**{field_name: None})
1994
- )
1995
- if "standard_name" in self.initial:
1996
- items_to_exclude = items_to_exclude.exclude(
1997
- standard_name=self.initial["standard_name"]
1998
- )
1999
- query = (
2000
- IrradEventXRayData.objects.filter(q_criteria)
2001
- .values_list(field_name, flat=True)
2002
- .exclude(**{field_name + "__in": items_to_exclude})
2003
- .distinct()
2004
- .order_by(field_name)
2005
- )
2006
- query_choices = [("", "None")] + [(item, item) for item in query]
2007
-
2008
- initial_choices = (
2009
- StandardNames.objects.all()
2010
- .filter(modality="MG")
2011
- .exclude(**{field_name: None})
2012
- .order_by(field_name)
2013
- )
2014
- if "standard_name" in self.initial:
2015
- initial_choices = initial_choices.filter(
2016
- standard_name=self.initial["standard_name"]
2017
- )
2018
-
2019
- self.initial[field_name] = list(
2020
- initial_choices.values_list(field_name, flat=True)
2021
- )
2022
-
2023
- self.fields[field_name] = forms.MultipleChoiceField(
2024
- choices=query_choices,
2025
- required=False,
2026
- widget=FilteredSelectMultiple(label_name.lower() + "s", is_stacked=False),
2027
- )
2028
-
2029
- class Media:
2030
- css = {
2031
- "all": (
2032
- os.path.join(settings.BASE_DIR, "/static/admin/css/widgets.css"),
2033
- ),
2034
- }
2035
- js = ("/admin/jsi18n",)
2036
-
2037
-
2038
- class StandardNameFormRF(StandardNameFormBase):
2039
- """Form for configuring standard names for study description, requested procedure, procedure and acquisition name"""
2040
-
2041
- def __init__(self, *args, **kwargs):
2042
- super(StandardNameFormRF, self).__init__(*args, **kwargs)
2043
- self.fields["modality"].initial = "RF"
2044
-
2045
- all_studies = GeneralStudyModuleAttr.objects.filter(modality_type__iexact="RF")
2046
-
2047
- field_names = [
2048
- ("study_description", "Study description"),
2049
- ("requested_procedure_code_meaning", "Requested procedure name"),
2050
- ("procedure_code_meaning", "Procedure name"),
2051
- ]
2052
-
2053
- for field_name, label_name in field_names:
2054
- # Exclude items already in the RF standard names entries except for the current value of the field
2055
- items_to_exclude = (
2056
- StandardNames.objects.all()
2057
- .filter(modality="RF")
2058
- .values(field_name)
2059
- .exclude(**{field_name: None})
2060
- )
2061
- if "standard_name" in self.initial:
2062
- items_to_exclude = items_to_exclude.exclude(
2063
- standard_name=self.initial["standard_name"]
2064
- )
2065
-
2066
- query = (
2067
- all_studies.values_list(field_name, flat=True)
2068
- .exclude(**{field_name + "__in": items_to_exclude})
2069
- .distinct()
2070
- .order_by(field_name)
2071
- )
2072
- query_choices = [("", "None")] + [(item, item) for item in query]
2073
-
2074
- initial_choices = (
2075
- StandardNames.objects.all()
2076
- .filter(modality="RF")
2077
- .exclude(**{field_name: None})
2078
- .order_by(field_name)
2079
- )
2080
- if "standard_name" in self.initial:
2081
- initial_choices = initial_choices.filter(
2082
- standard_name=self.initial["standard_name"]
2083
- )
2084
-
2085
- self.initial[field_name] = list(
2086
- initial_choices.values_list(field_name, flat=True)
2087
- )
2088
-
2089
- self.fields[field_name] = forms.MultipleChoiceField(
2090
- choices=query_choices,
2091
- required=False,
2092
- widget=FilteredSelectMultiple(
2093
- label_name.lower() + "s", is_stacked=False
2094
- ),
2095
- )
2096
-
2097
- q = ["RF"]
2098
- q_criteria = reduce(
2099
- operator.or_,
2100
- (
2101
- Q(
2102
- projection_xray_radiation_dose__general_study_module_attributes__modality_type__icontains=item
2103
- )
2104
- for item in q
2105
- ),
2106
- )
2107
- field_name, label_name = ("acquisition_protocol", "Acquisition protocol name")
2108
- items_to_exclude = (
2109
- StandardNames.objects.all().values(field_name).exclude(**{field_name: None})
2110
- )
2111
- if "standard_name" in self.initial:
2112
- items_to_exclude = items_to_exclude.exclude(
2113
- standard_name=self.initial["standard_name"]
2114
- )
2115
- query = (
2116
- IrradEventXRayData.objects.filter(q_criteria)
2117
- .values_list(field_name, flat=True)
2118
- .exclude(**{field_name + "__in": items_to_exclude})
2119
- .distinct()
2120
- .order_by(field_name)
2121
- )
2122
- query_choices = [("", "None")] + [(item, item) for item in query]
2123
-
2124
- initial_choices = (
2125
- StandardNames.objects.all()
2126
- .filter(modality="RF")
2127
- .exclude(**{field_name: None})
2128
- .order_by(field_name)
2129
- )
2130
- if "standard_name" in self.initial:
2131
- initial_choices = initial_choices.filter(
2132
- standard_name=self.initial["standard_name"]
2133
- )
2134
-
2135
- self.initial[field_name] = list(
2136
- initial_choices.values_list(field_name, flat=True)
2137
- )
2138
-
2139
- self.fields[field_name] = forms.MultipleChoiceField(
2140
- choices=query_choices,
2141
- required=False,
2142
- widget=FilteredSelectMultiple(label_name.lower() + "s", is_stacked=False),
2143
- )
2144
-
2145
- class Media:
2146
- css = {
2147
- "all": (
2148
- os.path.join(settings.BASE_DIR, "/static/admin/css/widgets.css"),
2149
- ),
2150
- }
2151
- js = ("/admin/jsi18n",)
2152
-
2153
-
2154
- class StandardNameSettingsForm(forms.ModelForm):
2155
- """Form for configuring whether standard names are shown / used"""
2156
-
2157
- def __init__(self, *args, **kwargs):
2158
- super(StandardNameSettingsForm, self).__init__(*args, **kwargs)
2159
- self.helper = FormHelper(self)
2160
- self.helper.form_class = "form-horizontal"
2161
- self.helper.layout = Layout(
2162
- Div("enable_standard_names"),
2163
- FormActions(Submit("submit", "Submit")),
2164
- )
2165
-
2166
- class Meta(object):
2167
- model = StandardNameSettings
2168
- fields = ["enable_standard_names"]
2169
-
2170
-
2171
- class SkinDoseMapCalcSettingsForm(forms.ModelForm):
2172
- """Form for configuring whether skin dose maps are shown / calculated"""
2173
-
2174
- def __init__(self, *args, **kwargs):
2175
- super(SkinDoseMapCalcSettingsForm, self).__init__(*args, **kwargs)
2176
- self.helper = FormHelper(self)
2177
- self.helper.form_class = "form-horizontal"
2178
- self.helper.layout = Layout(
2179
- Div("enable_skin_dose_maps", "calc_on_import", "allow_safelist_modify"),
2180
- FormActions(Submit("submit", "Submit")),
2181
- )
2182
-
2183
- class Meta(object):
2184
- model = SkinDoseMapCalcSettings
2185
- fields = ["enable_skin_dose_maps", "calc_on_import", "allow_safelist_modify"]
2186
-
2187
-
2188
- class NotPatientNameForm(forms.ModelForm):
2189
- """Form for configuring not-patient name patterns"""
2190
-
2191
- def __init__(self, *args, **kwargs):
2192
- super(NotPatientNameForm, self).__init__(*args, **kwargs)
2193
- self.helper = FormHelper(self)
2194
- self.helper.form_class = "form-horizontal"
2195
- self.helper.label_class = "col-md-8"
2196
- self.helper.field_class = "col-md-4"
2197
- self.helper.layout = Layout(
2198
- Div("not_patient_name"),
2199
- FormActions(Submit("submit", "Submit")),
2200
- Div(
2201
- HTML(
2202
- """
2203
- <div class="col-lg-4 col-lg-offset-4">
2204
- <a href='"""
2205
- + reverse("not_patient_indicators")
2206
- + """' role="button" class="btn btn-default">
2207
- Cancel and return to not-patient indicator summary page
2208
- </a>
2209
- </div>
2210
- """
2211
- )
2212
- ),
2213
- )
2214
-
2215
- class Meta(object):
2216
- model = NotPatientIndicatorsName
2217
- fields = ["not_patient_name"]
2218
- labels = {"not_patient_name": "pattern for name matching"}
2219
-
2220
-
2221
- class NotPatientIDForm(forms.ModelForm):
2222
- """Form for configuring not-patient ID patterns"""
2223
-
2224
- def __init__(self, *args, **kwargs):
2225
- super(NotPatientIDForm, self).__init__(*args, **kwargs)
2226
- self.helper = FormHelper(self)
2227
- self.helper.form_class = "form-horizontal"
2228
- self.helper.label_class = "col-md-8"
2229
- self.helper.field_class = "col-md-4"
2230
- self.helper.layout = Layout(
2231
- Div("not_patient_id"),
2232
- FormActions(Submit("submit", "Submit")),
2233
- Div(
2234
- HTML(
2235
- """
2236
- <div class="col-lg-4 col-lg-offset-4">
2237
- <a href='"""
2238
- + reverse("not_patient_indicators")
2239
- + """' role="button" class="btn btn-default">
2240
- Cancel and return to not-patient indicator summary page
2241
- </a>
2242
- </div>
2243
- """
2244
- )
2245
- ),
2246
- )
2247
-
2248
- class Meta(object):
2249
- model = NotPatientIndicatorsID
2250
- fields = ["not_patient_id"]
2251
- labels = {"not_patient_id": "pattern for ID matching"}
2252
-
2253
-
2254
- class SkinSafeListForm(forms.ModelForm):
2255
-
2256
- """Form for adding/updating/removing system from openSkin safe list"""
2257
-
2258
- class Meta(object):
2259
- model = OpenSkinSafeList
2260
- fields = ["manufacturer", "manufacturer_model_name", "software_version"]
2261
-
2262
-
2263
- class BackgroundTaskMaximumRowsForm(forms.ModelForm):
2264
- """Form for configuring the maximum number of rows in the BackgroundTask table"""
2265
-
2266
- def __init__(self, *args, **kwargs):
2267
- super(BackgroundTaskMaximumRowsForm, self).__init__(*args, **kwargs)
2268
- self.helper = FormHelper(self)
2269
- self.helper.form_class = "form-horizontal"
2270
- self.helper.layout = Layout(
2271
- Div("max_background_task_rows"),
2272
- FormActions(Submit("submit", "Submit")),
2273
- )
2274
-
2275
- class Meta(object):
2276
- model = BackgroundTaskMaximumRows
2277
- fields = ["max_background_task_rows"]
1
+ # pylint: disable=too-many-lines
2
+ # This Python file uses the following encoding: utf-8
3
+ # OpenREM - Radiation Exposure Monitoring tools for the physicist
4
+ # Copyright (C) 2019 The Royal Marsden NHS Foundation Trust
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # Additional permission under section 7 of GPLv3:
17
+ # You shall not make any use of the name of The Royal Marsden NHS
18
+ # Foundation trust in connection with this Program in any press or
19
+ # other public announcement without the prior written consent of
20
+ # The Royal Marsden NHS Foundation Trust.
21
+ #
22
+ # You should have received a copy of the GNU General Public License
23
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
24
+
25
+ """
26
+ .. module:: forms
27
+ :synopsis: Django forms definitions
28
+ """
29
+
30
+ import os
31
+ import logging
32
+ import operator
33
+ from functools import reduce
34
+
35
+ from django import forms
36
+ from django.db.models import Q
37
+ from django.contrib.admin.widgets import FilteredSelectMultiple
38
+ from django.conf import settings
39
+ from django.utils.safestring import mark_safe
40
+ from django.urls import reverse
41
+ from django.utils.translation import gettext as _
42
+ from crispy_forms.helper import FormHelper
43
+ from crispy_forms.layout import Layout, Submit, HTML, Div
44
+ from crispy_forms.bootstrap import (
45
+ FormActions,
46
+ PrependedText,
47
+ InlineCheckboxes,
48
+ Accordion,
49
+ AccordionGroup,
50
+ )
51
+
52
+ from .models import (
53
+ DicomDeleteSettings,
54
+ DicomRemoteQR,
55
+ DicomStoreSCP,
56
+ SkinDoseMapCalcSettings,
57
+ NotPatientIndicatorsName,
58
+ NotPatientIndicatorsID,
59
+ HighDoseMetricAlertSettings,
60
+ CommonVariables,
61
+ OpenSkinSafeList,
62
+ StandardNames,
63
+ StandardNameSettings,
64
+ GeneralStudyModuleAttr,
65
+ CtIrradiationEventData,
66
+ IrradEventXRayData,
67
+ BackgroundTaskMaximumRows,
68
+ )
69
+
70
+ logger = logging.getLogger()
71
+
72
+
73
+ class SizeUploadForm(forms.Form):
74
+ """Form for patient size csv file upload"""
75
+
76
+ sizefile = forms.FileField(label=_("Select a file"))
77
+
78
+
79
+ class SizeHeadersForm(forms.Form):
80
+ """Form for csv column header patient size imports through the web interface"""
81
+
82
+ height_field = forms.ChoiceField(choices="")
83
+ weight_field = forms.ChoiceField(choices="")
84
+ id_field = forms.ChoiceField(choices="")
85
+ id_type = forms.ChoiceField(choices="")
86
+ overwrite = forms.BooleanField(initial=False, required=False)
87
+
88
+ def __init__(self, my_choice=None, **kwargs):
89
+ super(SizeHeadersForm, self).__init__(**kwargs)
90
+ if my_choice:
91
+ self.fields["height_field"] = forms.ChoiceField(
92
+ choices=my_choice, widget=forms.Select(attrs={"class": "form-control"})
93
+ )
94
+ self.fields["weight_field"] = forms.ChoiceField(
95
+ choices=my_choice, widget=forms.Select(attrs={"class": "form-control"})
96
+ )
97
+ self.fields["id_field"] = forms.ChoiceField(
98
+ choices=my_choice, widget=forms.Select(attrs={"class": "form-control"})
99
+ )
100
+ ID_TYPES = (
101
+ ("acc-no", _("Accession Number")),
102
+ ("si-uid", _("Study instance UID")),
103
+ )
104
+ self.fields["id_type"] = forms.ChoiceField(
105
+ choices=ID_TYPES, widget=forms.Select(attrs={"class": "form-control"})
106
+ )
107
+
108
+
109
+ class itemsPerPageForm(forms.Form):
110
+ itemsPerPage = forms.ChoiceField(
111
+ label=_("Items per page"),
112
+ choices=CommonVariables.ITEMS_PER_PAGE,
113
+ required=False,
114
+ )
115
+
116
+
117
+ class DXChartOptionsForm(forms.Form):
118
+ """Form for DX chart options"""
119
+
120
+ plotCharts = forms.BooleanField(label=_("Plot charts?"), required=False)
121
+ plotCharts.group = "PlotCharts"
122
+ plotDXAcquisitionMeanDAPOverTimePeriod = forms.ChoiceField(
123
+ label="Time period", choices=CommonVariables.TIME_PERIOD, required=False
124
+ )
125
+ plotDXAcquisitionMeanDAPOverTimePeriod.group = "General"
126
+ plotAverageChoice = forms.MultipleChoiceField(
127
+ label="Average plots",
128
+ choices=CommonVariables.AVERAGES,
129
+ required=False,
130
+ widget=forms.CheckboxSelectMultiple(attrs={"class": "CheckboxSelectMultiple"}),
131
+ )
132
+ plotAverageChoice.group = "General"
133
+ plotGrouping = forms.ChoiceField(
134
+ label=mark_safe("Grouping choice"), # nosec
135
+ choices=CommonVariables.CHART_GROUPING,
136
+ required=False,
137
+ )
138
+ plotGrouping.group = "General"
139
+ plotSeriesPerSystem = forms.BooleanField(
140
+ label="Plot a series per system", required=False
141
+ )
142
+ plotSeriesPerSystem.group = "General"
143
+ plotHistograms = forms.BooleanField(
144
+ label="Calculate histogram data", required=False
145
+ )
146
+ plotHistograms.group = "General"
147
+ plotDXInitialSortingChoice = forms.ChoiceField(
148
+ label="Chart sorting", choices=CommonVariables.SORTING_CHOICES, required=False
149
+ )
150
+ plotDXInitialSortingChoice.group = "General"
151
+ plotInitialSortingDirection = forms.ChoiceField(
152
+ label="Sorting direction",
153
+ choices=CommonVariables.SORTING_DIRECTION,
154
+ required=False,
155
+ )
156
+ plotInitialSortingDirection.group = "General"
157
+ plotDXAcquisitionFreq = forms.BooleanField(
158
+ label=_("Acquisition frequency"), required=False
159
+ )
160
+ plotDXAcquisitionFreq.group = "Acquisition protocol"
161
+ plotDXAcquisitionMeanDAP = forms.BooleanField(
162
+ label=_("Acquisition DAP"), required=False
163
+ )
164
+ plotDXAcquisitionMeanDAP.group = "Acquisition protocol"
165
+ plotDXAcquisitionMeanmAs = forms.BooleanField(
166
+ label=_("Acquisition mAs"), required=False
167
+ )
168
+ plotDXAcquisitionMeanmAs.group = "Acquisition protocol"
169
+ plotDXAcquisitionMeankVp = forms.BooleanField(
170
+ label=_("Acquisition kVp"), required=False
171
+ )
172
+ plotDXAcquisitionMeankVp.group = "Acquisition protocol"
173
+ plotDXAcquisitionMeanDAPOverTime = forms.BooleanField(
174
+ label=_("Acquisition DAP over time"), required=False
175
+ )
176
+ plotDXAcquisitionMeanDAPOverTime.group = "Acquisition protocol"
177
+ plotDXAcquisitionMeanmAsOverTime = forms.BooleanField(
178
+ label=_("Acquisition mAs over time"), required=False
179
+ )
180
+ plotDXAcquisitionMeanmAsOverTime.group = "Acquisition protocol"
181
+ plotDXAcquisitionMeankVpOverTime = forms.BooleanField(
182
+ label=_("Acquisition kVp over time"), required=False
183
+ )
184
+ plotDXAcquisitionMeankVpOverTime.group = "Acquisition protocol"
185
+ plotDXAcquisitionDAPvsMass = forms.BooleanField(
186
+ label=_("Acquisition DAP vs mass"), required=False
187
+ )
188
+ plotDXAcquisitionDAPvsMass.group = "Acquisition protocol"
189
+ plotDXStudyFreq = forms.BooleanField(label=_("Study frequency"), required=False)
190
+ plotDXStudyFreq.group = "Study description"
191
+ plotDXStudyMeanDAP = forms.BooleanField(label=_("Study DAP"), required=False)
192
+ plotDXStudyMeanDAP.group = "Study description"
193
+ plotDXStudyDAPvsMass = forms.BooleanField(
194
+ label=_("Study DAP vs mass"), required=False
195
+ )
196
+ plotDXStudyDAPvsMass.group = "Study description"
197
+ plotDXStudyPerDayAndHour = forms.BooleanField(
198
+ label=_("Study workload"), required=False
199
+ )
200
+ plotDXStudyPerDayAndHour.group = "Study description"
201
+ plotDXRequestFreq = forms.BooleanField(
202
+ label=_("Requested procedure frequency"), required=False
203
+ )
204
+ plotDXRequestFreq.group = "Requested procedure"
205
+ plotDXRequestMeanDAP = forms.BooleanField(
206
+ label=_("Requested procedure DAP"), required=False
207
+ )
208
+ plotDXRequestMeanDAP.group = "Requested procedure"
209
+ plotDXRequestDAPvsMass = forms.BooleanField(
210
+ label=_("Requested procedure DAP vs mass"), required=False
211
+ )
212
+ plotDXRequestDAPvsMass.group = "Requested procedure"
213
+
214
+
215
+ class DXChartOptionsFormIncStandard(DXChartOptionsForm):
216
+ plotDXStandardAcquisitionFreq = forms.BooleanField(
217
+ label="Standard acquisition name frequency", required=False
218
+ )
219
+ plotDXStandardAcquisitionFreq.group = "Standard acquisition name"
220
+ plotDXStandardAcquisitionMeanDAP = forms.BooleanField(
221
+ label="Standard acquisition name DAP", required=False
222
+ )
223
+ plotDXStandardAcquisitionMeanDAP.group = "Standard acquisition name"
224
+ plotDXStandardAcquisitionMeanmAs = forms.BooleanField(
225
+ label="Standard acquisition name mAs", required=False
226
+ )
227
+ plotDXStandardAcquisitionMeanmAs.group = "Standard acquisition name"
228
+ plotDXStandardAcquisitionMeankVp = forms.BooleanField(
229
+ label="Standard acquisition name kVp", required=False
230
+ )
231
+ plotDXStandardAcquisitionMeankVp.group = "Standard acquisition name"
232
+ plotDXStandardAcquisitionMeanDAPOverTime = forms.BooleanField(
233
+ label="Standard acquisition name DAP over time", required=False
234
+ )
235
+ plotDXStandardAcquisitionMeanDAPOverTime.group = "Standard acquisition name"
236
+ plotDXStandardAcquisitionMeanmAsOverTime = forms.BooleanField(
237
+ label="Standard acquisition name mAs over time", required=False
238
+ )
239
+ plotDXStandardAcquisitionMeanmAsOverTime.group = "Standard acquisition name"
240
+ plotDXStandardAcquisitionMeankVpOverTime = forms.BooleanField(
241
+ label="Standard acquisition name kVp over time", required=False
242
+ )
243
+ plotDXStandardAcquisitionMeankVpOverTime.group = "Standard acquisition name"
244
+ plotDXStandardAcquisitionDAPvsMass = forms.BooleanField(
245
+ label="Standard acquisition name DAP vs mass", required=False
246
+ )
247
+ plotDXStandardAcquisitionDAPvsMass.group = "Standard acquisition name"
248
+
249
+ plotDXStandardStudyFreq = forms.BooleanField(
250
+ label="Standard study name frequency", required=False
251
+ )
252
+ plotDXStandardStudyFreq.group = "Standard study name"
253
+ plotDXStandardStudyMeanDAP = forms.BooleanField(
254
+ label="Standard study name DAP", required=False
255
+ )
256
+ plotDXStandardStudyMeanDAP.group = "Standard study name"
257
+ plotDXStandardStudyDAPvsMass = forms.BooleanField(
258
+ label="Standard study name DAP vs mass", required=False
259
+ )
260
+ plotDXStandardStudyDAPvsMass.group = "Standard study name"
261
+ plotDXStandardStudyPerDayAndHour = forms.BooleanField(
262
+ label="Standard study name workload", required=False
263
+ )
264
+ plotDXStandardStudyPerDayAndHour.group = "Standard study name"
265
+
266
+
267
+ class CTChartOptionsForm(forms.Form):
268
+ """Form for CT chart options"""
269
+
270
+ plotCharts = forms.BooleanField(label="Plot charts?", required=False)
271
+ plotCharts.group = "PlotCharts"
272
+ plotCTOverTimePeriod = forms.ChoiceField(
273
+ label="Time period", choices=CommonVariables.TIME_PERIOD, required=False
274
+ )
275
+ plotCTOverTimePeriod.group = "General"
276
+ plotAverageChoice = forms.MultipleChoiceField(
277
+ label=_("Average plots"),
278
+ choices=CommonVariables.AVERAGES,
279
+ required=False,
280
+ widget=forms.CheckboxSelectMultiple(attrs={"class": "CheckboxSelectMultiple"}),
281
+ )
282
+ plotAverageChoice.group = "General"
283
+ plotGrouping = forms.ChoiceField(
284
+ label=mark_safe(_("Grouping choice")), # nosec
285
+ choices=CommonVariables.CHART_GROUPING,
286
+ required=False,
287
+ )
288
+ plotGrouping.group = "General"
289
+ plotSeriesPerSystem = forms.BooleanField(
290
+ label=_("Plot a series per system"), required=False
291
+ )
292
+ plotSeriesPerSystem.group = "General"
293
+ plotHistograms = forms.BooleanField(
294
+ label=_("Calculate histogram data"), required=False
295
+ )
296
+ plotHistograms.group = "General"
297
+ plotCTInitialSortingChoice = forms.ChoiceField(
298
+ label=_("Chart sorting"),
299
+ choices=CommonVariables.SORTING_CHOICES,
300
+ required=False,
301
+ )
302
+ plotCTInitialSortingChoice.group = "General"
303
+ plotInitialSortingDirection = forms.ChoiceField(
304
+ label=_("Sorting direction"),
305
+ choices=CommonVariables.SORTING_DIRECTION,
306
+ required=False,
307
+ )
308
+ plotInitialSortingDirection.group = "General"
309
+
310
+ plotCTAcquisitionFreq = forms.BooleanField(
311
+ label=_("Acquisition frequency"), required=False
312
+ )
313
+ plotCTAcquisitionFreq.group = "Acquisition protocol"
314
+ plotCTAcquisitionMeanDLP = forms.BooleanField(
315
+ label=_("Acquisition DLP"), required=False
316
+ )
317
+ plotCTAcquisitionMeanDLP.group = "Acquisition protocol"
318
+ plotCTAcquisitionMeanCTDI = forms.BooleanField(
319
+ label=mark_safe(_("Acquisition CTDI<sub>vol</sub>")), required=False # nosec
320
+ )
321
+ plotCTAcquisitionMeanCTDI.group = "Acquisition protocol"
322
+ plotCTAcquisitionDLPOverTime = forms.BooleanField(
323
+ label=_("Acquisition DLP over time"), required=False
324
+ )
325
+ plotCTAcquisitionDLPOverTime.group = "Acquisition protocol"
326
+ plotCTAcquisitionCTDIOverTime = forms.BooleanField(
327
+ label=mark_safe(_("Acquisition CTDI<sub>vol</sub> over time")), # nosec
328
+ required=False,
329
+ )
330
+ plotCTAcquisitionCTDIOverTime.group = "Acquisition protocol"
331
+ plotCTAcquisitionDLPvsMass = forms.BooleanField(
332
+ label=_("Acquisition DLP vs mass"), required=False
333
+ )
334
+ plotCTAcquisitionDLPvsMass.group = "Acquisition protocol"
335
+ plotCTAcquisitionCTDIvsMass = forms.BooleanField(
336
+ label=mark_safe(_("Acquisition CTDI<sub>vol</sub> vs mass")), # nosec
337
+ required=False,
338
+ )
339
+ plotCTAcquisitionCTDIvsMass.group = "Acquisition protocol"
340
+ plotCTAcquisitionTypes = forms.MultipleChoiceField(
341
+ label=mark_safe( # nosec
342
+ _(
343
+ "Acquisition types to include<br/>in acquisition-level chart<br/>calculations"
344
+ )
345
+ ),
346
+ choices=CommonVariables.CT_ACQUISITION_TYPES,
347
+ required=False,
348
+ widget=forms.CheckboxSelectMultiple(attrs={"class": "CheckboxSelectMultiple"}),
349
+ )
350
+ plotCTAcquisitionTypes.group = "Acquisition protocol"
351
+
352
+ plotCTStudyFreq = forms.BooleanField(label="Study frequency", required=False)
353
+ plotCTStudyFreq.group = "Study description"
354
+ plotCTStudyMeanDLP = forms.BooleanField(label="Study DLP", required=False)
355
+ plotCTStudyMeanDLP.group = "Study description"
356
+ plotCTStudyMeanCTDI = forms.BooleanField(
357
+ label=mark_safe(_("Study CTDI<sub>vol</sub>")), required=False # nosec
358
+ )
359
+ plotCTStudyMeanCTDI.group = "Study description"
360
+ plotCTStudyNumEvents = forms.BooleanField(label="Study events", required=False)
361
+ plotCTStudyNumEvents.group = "Study description"
362
+ plotCTStudyMeanDLPOverTime = forms.BooleanField(
363
+ label=_("Study DLP over time"), required=False
364
+ )
365
+ plotCTStudyMeanDLPOverTime.group = "Study description"
366
+ plotCTStudyPerDayAndHour = forms.BooleanField(
367
+ label=_("Study workload"), required=False
368
+ )
369
+ plotCTStudyPerDayAndHour.group = "Study description"
370
+
371
+ plotCTRequestFreq = forms.BooleanField(
372
+ label=_("Requested procedure frequency"), required=False
373
+ )
374
+ plotCTRequestFreq.group = "Requested procedure"
375
+ plotCTRequestMeanDLP = forms.BooleanField(
376
+ label=_("Requested procedure DLP"), required=False
377
+ )
378
+ plotCTRequestMeanDLP.group = "Requested procedure"
379
+ plotCTRequestNumEvents = forms.BooleanField(
380
+ label=_("Requested procedure events"), required=False
381
+ )
382
+ plotCTRequestNumEvents.group = "Requested procedure"
383
+ plotCTRequestDLPOverTime = forms.BooleanField(
384
+ label=_("Requested procedure DLP over time"), required=False
385
+ )
386
+ plotCTRequestDLPOverTime.group = "Requested procedure"
387
+
388
+
389
+ class CTChartOptionsFormIncStandard(CTChartOptionsForm):
390
+ plotCTStandardAcquisitionFreq = forms.BooleanField(
391
+ label="Standard acquisition name frequency", required=False
392
+ )
393
+ plotCTStandardAcquisitionFreq.group = "Standard acquisition name"
394
+ plotCTStandardAcquisitionMeanDLP = forms.BooleanField(
395
+ label="Standard acquisition name DLP", required=False
396
+ )
397
+ plotCTStandardAcquisitionMeanDLP.group = "Standard acquisition name"
398
+ plotCTStandardAcquisitionMeanCTDI = forms.BooleanField(
399
+ label=mark_safe("Standard acquisition name CTDI<sub>vol</sub>"), # nosec
400
+ required=False,
401
+ )
402
+ plotCTStandardAcquisitionMeanCTDI.group = "Standard acquisition name"
403
+ plotCTStandardAcquisitionDLPOverTime = forms.BooleanField(
404
+ label="Standard acquisition name DLP over time", required=False
405
+ )
406
+ plotCTStandardAcquisitionDLPOverTime.group = "Standard acquisition name"
407
+ plotCTStandardAcquisitionCTDIOverTime = forms.BooleanField(
408
+ label=mark_safe( # nosec
409
+ "Standard acquisition name CTDI<sub>vol</sub> over time"
410
+ ),
411
+ required=False,
412
+ )
413
+ plotCTStandardAcquisitionCTDIOverTime.group = "Standard acquisition name"
414
+ plotCTStandardAcquisitionDLPvsMass = forms.BooleanField(
415
+ label="Standard acquisition name DLP vs mass", required=False
416
+ )
417
+ plotCTStandardAcquisitionDLPvsMass.group = "Standard acquisition name"
418
+ plotCTStandardAcquisitionCTDIvsMass = forms.BooleanField(
419
+ label=mark_safe( # nosec
420
+ "Standard acquisition name CTDI<sub>vol</sub> vs mass"
421
+ ),
422
+ required=False,
423
+ )
424
+ plotCTStandardAcquisitionCTDIvsMass.group = "Standard acquisition name"
425
+
426
+ plotCTStandardStudyFreq = forms.BooleanField(
427
+ label="Standard study frequency", required=False
428
+ )
429
+ plotCTStandardStudyFreq.group = "Standard study name"
430
+ plotCTStandardStudyMeanDLP = forms.BooleanField(
431
+ label="Standard study DLP", required=False
432
+ )
433
+ plotCTStandardStudyMeanDLP.group = "Standard study name"
434
+ plotCTStandardStudyNumEvents = forms.BooleanField(
435
+ label="Standard study events", required=False
436
+ )
437
+ plotCTStandardStudyNumEvents.group = "Standard study name"
438
+ plotCTStandardStudyMeanDLPOverTime = forms.BooleanField(
439
+ label="Standard study DLP over time", required=False
440
+ )
441
+ plotCTStandardStudyMeanDLPOverTime.group = "Standard study name"
442
+ plotCTStandardStudyPerDayAndHour = forms.BooleanField(
443
+ label="Standard study workload", required=False
444
+ )
445
+ plotCTStandardStudyPerDayAndHour.group = "Standard study name"
446
+
447
+
448
+ class NMChartOptionsForm(forms.Form):
449
+ """
450
+ Form for NM chart options
451
+ """
452
+
453
+ plotCharts = forms.BooleanField(label=_("Plot charts?"), required=False)
454
+
455
+ plotNMStudyFreq = forms.BooleanField(label=_("Study frequency"), required=False)
456
+ plotNMStudyPerDayAndHour = forms.BooleanField(
457
+ label=_("Study workload"), required=False
458
+ )
459
+ plotNMInjectedDosePerStudy = forms.BooleanField(
460
+ label=_("Injected dose per study"), required=False
461
+ )
462
+ plotNMInjectedDoseOverTime = forms.BooleanField(
463
+ label=_("Injected dose over time"), required=False
464
+ )
465
+ plotNMInjectedDoseOverWeight = forms.BooleanField(
466
+ label=_("Injected dose vs mass"), required=False
467
+ )
468
+ plotNMOverTimePeriod = forms.ChoiceField(
469
+ label=_("Time period"), choices=CommonVariables.TIME_PERIOD, required=False
470
+ )
471
+ plotAverageChoice = forms.MultipleChoiceField(
472
+ label=_("Average plots"),
473
+ choices=CommonVariables.AVERAGES,
474
+ required=False,
475
+ widget=forms.CheckboxSelectMultiple(attrs={"class": "CheckboxSelectMultiple"}),
476
+ )
477
+ plotGrouping = forms.ChoiceField(
478
+ label=mark_safe(_("Grouping choice")), # nosec
479
+ choices=CommonVariables.CHART_GROUPING,
480
+ required=False,
481
+ )
482
+ plotSeriesPerSystem = forms.BooleanField(
483
+ label=_("Plot a series per system"), required=False
484
+ )
485
+ plotHistograms = forms.BooleanField(
486
+ label=_("Calculate histogram data"), required=False
487
+ )
488
+ plotNMInitialSortingChoice = forms.ChoiceField(
489
+ label=_("Chart sorting"),
490
+ choices=CommonVariables.SORTING_CHOICES,
491
+ required=False,
492
+ )
493
+ plotInitialSortingDirection = forms.ChoiceField(
494
+ label=_("Sorting direction"),
495
+ choices=CommonVariables.SORTING_DIRECTION,
496
+ required=False,
497
+ )
498
+
499
+
500
+ class NMChartOptionsDisplayForm(forms.Form):
501
+ """
502
+ Form for NM chart display options
503
+ """
504
+
505
+ plotNMStudyFreq = forms.BooleanField(label=_("Study frequency"), required=False)
506
+ plotNMStudyPerDayAndHour = forms.BooleanField(
507
+ label=_("Study workload"), required=False
508
+ )
509
+ plotNMInjectedDosePerStudy = forms.BooleanField(
510
+ label=_("Injected Dose per Study"), required=False
511
+ )
512
+ plotNMInjectedDoseOverTime = forms.BooleanField(
513
+ label=_("Injected Dose over Time"), required=False
514
+ )
515
+ plotNMInjectedDoseOverWeight = forms.BooleanField(
516
+ label=_("Injected Dose over Weight"), required=False
517
+ )
518
+ plotNMOverTimePeriod = forms.ChoiceField(
519
+ label=_("Time period"), choices=CommonVariables.TIME_PERIOD, required=False
520
+ )
521
+ plotNMInitialSortingChoice = forms.ChoiceField(
522
+ label=_("Chart sorting"),
523
+ choices=CommonVariables.SORTING_CHOICES,
524
+ required=False,
525
+ )
526
+
527
+
528
+ class RFChartOptionsForm(forms.Form):
529
+ """Form for RF chart options"""
530
+
531
+ plotCharts = forms.BooleanField(label="Plot charts?", required=False)
532
+ plotCharts.group = "PlotCharts"
533
+ plotRFOverTimePeriod = forms.ChoiceField(
534
+ label="Time period", choices=CommonVariables.TIME_PERIOD, required=False
535
+ )
536
+ plotRFOverTimePeriod.group = "General"
537
+ plotAverageChoice = forms.MultipleChoiceField(
538
+ label=_("Average plots"),
539
+ choices=CommonVariables.AVERAGES,
540
+ required=False,
541
+ widget=forms.CheckboxSelectMultiple(attrs={"class": "CheckboxSelectMultiple"}),
542
+ )
543
+ plotAverageChoice.group = "General"
544
+ plotRFSplitByPhysician = forms.BooleanField(
545
+ label="Split plots by physician", required=False
546
+ )
547
+ plotRFSplitByPhysician.group = "General"
548
+ plotGrouping = forms.ChoiceField(
549
+ label=mark_safe(_("Grouping choice")), # nosec
550
+ choices=CommonVariables.CHART_GROUPING_RF,
551
+ required=False,
552
+ )
553
+ plotGrouping.group = "General"
554
+ plotSeriesPerSystem = forms.BooleanField(
555
+ label=_("Plot a series per system"), required=False
556
+ )
557
+ plotSeriesPerSystem.group = "General"
558
+ plotHistograms = forms.BooleanField(
559
+ label=_("Calculate histogram data"), required=False
560
+ )
561
+ plotHistograms.group = "General"
562
+ plotRFInitialSortingChoice = forms.ChoiceField(
563
+ label="Chart sorting", choices=CommonVariables.SORTING_CHOICES, required=False
564
+ )
565
+ plotRFInitialSortingChoice.group = "General"
566
+ plotInitialSortingDirection = forms.ChoiceField(
567
+ label=_("Sorting direction"),
568
+ choices=CommonVariables.SORTING_DIRECTION,
569
+ required=False,
570
+ )
571
+ plotInitialSortingDirection.group = "General"
572
+
573
+ plotRFStudyFreq = forms.BooleanField(label="Study frequency", required=False)
574
+ plotRFStudyFreq.group = "Study description"
575
+ plotRFStudyDAP = forms.BooleanField(label="Study DAP", required=False)
576
+ plotRFStudyDAP.group = "Study description"
577
+ plotRFStudyDAPOverTime = forms.BooleanField(
578
+ label=_("Study DAP over time"), required=False
579
+ )
580
+ plotRFStudyDAPOverTime.group = "Study description"
581
+ plotRFStudyPerDayAndHour = forms.BooleanField(
582
+ label=_("Study workload"), required=False
583
+ )
584
+ plotRFStudyPerDayAndHour.group = "Study description"
585
+
586
+ plotRFRequestFreq = forms.BooleanField(
587
+ label=_("Requested procedure frequency"), required=False
588
+ )
589
+ plotRFRequestFreq.group = "Requested procedure"
590
+ plotRFRequestDAP = forms.BooleanField(
591
+ label=_("Requested procedure DAP"), required=False
592
+ )
593
+ plotRFRequestDAP.group = "Requested procedure"
594
+ plotRFRequestDAPOverTime = forms.BooleanField(
595
+ label=_("Requested procedure DAP over time"), required=False
596
+ )
597
+ plotRFRequestDAPOverTime.group = "Requested procedure"
598
+
599
+
600
+ class RFChartOptionsFormIncStandard(RFChartOptionsForm):
601
+ plotRFStandardStudyFreq = forms.BooleanField(
602
+ label="Standard study name frequency", required=False
603
+ )
604
+ plotRFStandardStudyFreq.group = "Standard study name"
605
+ plotRFStandardStudyDAP = forms.BooleanField(
606
+ label="Standard study name DAP", required=False
607
+ )
608
+ plotRFStandardStudyDAP.group = "Standard study name"
609
+ plotRFStandardStudyDAPOverTime = forms.BooleanField(
610
+ label="Standard study name DAP over time", required=False
611
+ )
612
+ plotRFStandardStudyDAPOverTime.group = "Standard study name"
613
+ plotRFStandardStudyPerDayAndHour = forms.BooleanField(
614
+ label="Standard study name workload", required=False
615
+ )
616
+ plotRFStandardStudyPerDayAndHour.group = "Standard study name"
617
+
618
+
619
+ class RFChartOptionsDisplayForm(forms.Form):
620
+ """Form for RF chart display options"""
621
+
622
+ plotRFStudyFreq = forms.BooleanField(label=_("Study frequency"), required=False)
623
+ plotRFStudyDAP = forms.BooleanField(label=_("Study DAP"), required=False)
624
+ plotRFStudyDAPOverTime = forms.BooleanField(
625
+ label=_("Study DAP over time"), required=False
626
+ )
627
+ plotRFStudyPerDayAndHour = forms.BooleanField(
628
+ label=_("Study workload"), required=False
629
+ )
630
+ plotRFRequestFreq = forms.BooleanField(
631
+ label=_("Requested procedure frequency"), required=False
632
+ )
633
+ plotRFRequestDAP = forms.BooleanField(
634
+ label=_("Requested procedure DAP"), required=False
635
+ )
636
+ plotRFRequestDAPOverTime = forms.BooleanField(
637
+ label=_("Requested procedure DAP over time"), required=False
638
+ )
639
+ plotRFOverTimePeriod = forms.ChoiceField(
640
+ label=_("Time period"), choices=CommonVariables.TIME_PERIOD, required=False
641
+ )
642
+ plotRFSplitByPhysician = forms.BooleanField(
643
+ label=_("Split plots by physician"), required=False
644
+ )
645
+ plotRFInitialSortingChoice = forms.ChoiceField(
646
+ label=_("Default chart sorting"),
647
+ choices=CommonVariables.SORTING_CHOICES,
648
+ required=False,
649
+ )
650
+
651
+
652
+ class RFChartOptionsDisplayFormIncStandard(RFChartOptionsDisplayForm):
653
+ plotRFStandardStudyFreq = forms.BooleanField(
654
+ label="Standard study name frequency", required=False
655
+ )
656
+ plotRFStandardStudyDAP = forms.BooleanField(
657
+ label="Standard study name DAP", required=False
658
+ )
659
+ plotRFStandardStudyDAPOverTime = forms.BooleanField(
660
+ label="Standard study name DAP over time", required=False
661
+ )
662
+ plotRFStandardStudyPerDayAndHour = forms.BooleanField(
663
+ label="Standard study name workload", required=False
664
+ )
665
+
666
+ field_order = [
667
+ "plotRFStudyFreq",
668
+ "plotRFStudyDAP",
669
+ "plotRFStudyDAPOverTime",
670
+ "plotRFStudyPerDayAndHour",
671
+ "plotRFRequestFreq",
672
+ "plotRFRequestDAP",
673
+ "plotRFRequestDAPOverTime",
674
+ "plotRFStandardStudyFreq",
675
+ "plotRFStandardStudyDAP",
676
+ "plotRFStandardStudyDAPOverTime",
677
+ "plotRFStandardStudyPerDayAndHour",
678
+ "plotRFOverTimePeriod",
679
+ "plotRFSplitByPhysician",
680
+ "plotRFInitialSortingChoice",
681
+ ]
682
+
683
+
684
+ class MGChartOptionsForm(forms.Form):
685
+ """Form for MG chart options"""
686
+
687
+ plotCharts = forms.BooleanField(label="Plot charts?", required=False)
688
+ plotCharts.group = "PlotCharts"
689
+ plotMGOverTimePeriod = forms.ChoiceField(
690
+ label=_("Time period"), choices=CommonVariables.TIME_PERIOD, required=False
691
+ )
692
+ plotMGOverTimePeriod.group = "General"
693
+ plotAverageChoice = forms.MultipleChoiceField(
694
+ label=_("Average plots"),
695
+ choices=CommonVariables.AVERAGES,
696
+ required=False,
697
+ widget=forms.CheckboxSelectMultiple(attrs={"class": "CheckboxSelectMultiple"}),
698
+ )
699
+ plotAverageChoice.group = "General"
700
+ plotGrouping = forms.ChoiceField(
701
+ label=mark_safe(_("Grouping choice")), # nosec
702
+ choices=CommonVariables.CHART_GROUPING,
703
+ required=False,
704
+ )
705
+ plotGrouping.group = "General"
706
+ plotSeriesPerSystem = forms.BooleanField(
707
+ label=_("Plot a series per system"), required=False
708
+ )
709
+ plotSeriesPerSystem.group = "General"
710
+ plotHistograms = forms.BooleanField(
711
+ label=_("Calculate histogram data"), required=False
712
+ )
713
+ plotHistograms.group = "General"
714
+ plotMGInitialSortingChoice = forms.ChoiceField(
715
+ label=_("Chart sorting"),
716
+ choices=CommonVariables.SORTING_CHOICES,
717
+ required=False,
718
+ )
719
+ plotMGInitialSortingChoice.group = "General"
720
+ plotInitialSortingDirection = forms.ChoiceField(
721
+ label=_("Sorting direction"),
722
+ choices=CommonVariables.SORTING_DIRECTION,
723
+ required=False,
724
+ )
725
+ plotInitialSortingDirection.group = "General"
726
+ plotMGacquisitionFreq = forms.BooleanField(
727
+ label="Acquisition frequency", required=False
728
+ )
729
+ plotMGacquisitionFreq.group = "Acquisition protocol"
730
+ plotMGaverageAGD = forms.BooleanField(
731
+ label="Acquisition average AGD", required=False
732
+ )
733
+ plotMGaverageAGD.group = "Acquisition protocol"
734
+ plotMGaverageAGDvsThickness = forms.BooleanField(
735
+ label="Acquisition average AGD vs. compressed thickness", required=False
736
+ )
737
+ plotMGaverageAGDvsThickness.group = "Acquisition protocol"
738
+ plotMGAcquisitionAGDOverTime = forms.BooleanField(
739
+ label="Acquisition AGD over time", required=False
740
+ )
741
+ plotMGAcquisitionAGDOverTime.group = "Acquisition protocol"
742
+ plotMGAGDvsThickness = forms.BooleanField(
743
+ label="Acquisition AGD vs. compressed thickness", required=False
744
+ )
745
+ plotMGAGDvsThickness.group = "Acquisition protocol"
746
+ plotMGmAsvsThickness = forms.BooleanField(
747
+ label="Acquisition mAs vs. compressed thickness", required=False
748
+ )
749
+ plotMGmAsvsThickness.group = "Acquisition protocol"
750
+ plotMGkVpvsThickness = forms.BooleanField(
751
+ label="Acquisition kVp vs. compressed thickness", required=False
752
+ )
753
+ plotMGkVpvsThickness.group = "Acquisition protocol"
754
+ plotMGStudyPerDayAndHour = forms.BooleanField(
755
+ label="Study workload", required=False
756
+ )
757
+ plotMGStudyPerDayAndHour.group = "Study description"
758
+
759
+
760
+ class MGChartOptionsFormIncStandard(MGChartOptionsForm):
761
+ plotMGStandardAcquisitionFreq = forms.BooleanField(
762
+ label="Standard acquisition name frequency", required=False
763
+ )
764
+ plotMGStandardAcquisitionFreq.group = "Standard acquisition name"
765
+ plotMGStandardAverageAGD = forms.BooleanField(
766
+ label="Standard acquisition name average AGD", required=False
767
+ )
768
+ plotMGStandardAverageAGD.group = "Standard acquisition name"
769
+ plotMGStandardAverageAGDvsThickness = forms.BooleanField(
770
+ label="Standard acquisition name average AGD vs. compressed thickness",
771
+ required=False,
772
+ )
773
+ plotMGStandardAverageAGDvsThickness.group = "Standard acquisition name"
774
+ plotMGStandardAcquisitionAGDOverTime = forms.BooleanField(
775
+ label="Standard acquisition name AGD over time", required=False
776
+ )
777
+ plotMGStandardAcquisitionAGDOverTime.group = "Standard acquisition name"
778
+ plotMGStandardAGDvsThickness = forms.BooleanField(
779
+ label="Standard acquisition name AGD vs. compressed thickness", required=False
780
+ )
781
+ plotMGStandardAGDvsThickness.group = "Standard acquisition name"
782
+ plotMGStandardmAsvsThickness = forms.BooleanField(
783
+ label="Standard acquisition name mAs vs. compressed thickness", required=False
784
+ )
785
+ plotMGStandardmAsvsThickness.group = "Standard acquisition name"
786
+ plotMGStandardkVpvsThickness = forms.BooleanField(
787
+ label="Standard acquisition name kVp vs. compressed thickness", required=False
788
+ )
789
+ plotMGStandardkVpvsThickness.group = "Standard acquisition name"
790
+ plotMGStandardStudyPerDayAndHour = forms.BooleanField(
791
+ label="Standard study name workload", required=False
792
+ )
793
+ plotMGStandardStudyPerDayAndHour.group = "Standard study name"
794
+
795
+
796
+ class MGChartOptionsDisplayForm(forms.Form):
797
+ """Form for MG chart display options"""
798
+
799
+ plotMGacquisitionFreq = forms.BooleanField(
800
+ label=_("Acquisition frequency"), required=False
801
+ )
802
+ plotMGaverageAGD = forms.BooleanField(
803
+ label=_("Acquisition average AGD"), required=False
804
+ )
805
+ plotMGaverageAGDvsThickness = forms.BooleanField(
806
+ label=_("Acquisition average AGD vs. compressed thickness"), required=False
807
+ )
808
+ plotMGAcquisitionAGDOverTime = forms.BooleanField(
809
+ label=_("Acquisition AGD over time"), required=False
810
+ )
811
+ plotMGAGDvsThickness = forms.BooleanField(
812
+ label=_("Acquisition AGD vs. compressed thickness"), required=False
813
+ )
814
+ plotMGmAsvsThickness = forms.BooleanField(
815
+ label=_("Acquisition mAs vs. compressed thickness"), required=False
816
+ )
817
+ plotMGkVpvsThickness = forms.BooleanField(
818
+ label=_("Acquisition kVp vs. compressed thickness"), required=False
819
+ )
820
+ plotMGStudyPerDayAndHour = forms.BooleanField(
821
+ label=_("Study workload"), required=False
822
+ )
823
+ plotMGOverTimePeriod = forms.ChoiceField(
824
+ label=_("Time period"), choices=CommonVariables.TIME_PERIOD, required=False
825
+ )
826
+ plotMGInitialSortingChoice = forms.ChoiceField(
827
+ label=_("Chart sorting"),
828
+ choices=CommonVariables.SORTING_CHOICES,
829
+ required=False,
830
+ )
831
+
832
+
833
+ class MGChartOptionsDisplayFormIncStandard(MGChartOptionsDisplayForm):
834
+ plotMGStandardAcquisitionFreq = forms.BooleanField(
835
+ label="Standard acquisition name frequency", required=False
836
+ )
837
+ plotMGStandardAverageAGD = forms.BooleanField(
838
+ label="Standard acquisition name average AGD", required=False
839
+ )
840
+ plotMGStandardAverageAGDvsThickness = forms.BooleanField(
841
+ label="Standard acquisition name average AGD vs. compressed thickness",
842
+ required=False,
843
+ )
844
+ plotMGStandardAcquisitionAGDOverTime = forms.BooleanField(
845
+ label="Standard acquisition name AGD over time", required=False
846
+ )
847
+ plotMGStandardAGDvsThickness = forms.BooleanField(
848
+ label="Standard acquisition name AGD vs. compressed thickness", required=False
849
+ )
850
+ plotMGStandardmAsvsThickness = forms.BooleanField(
851
+ label="Standard acquisition name mAs vs. compressed thickness", required=False
852
+ )
853
+ plotMGStandardkVpvsThickness = forms.BooleanField(
854
+ label="Standard acquisition name kVp vs. compressed thickness", required=False
855
+ )
856
+ plotMGStandardStudyPerDayAndHour = forms.BooleanField(
857
+ label="Standard study name", required=False
858
+ )
859
+
860
+ field_order = [
861
+ "plotMGacquisitionFreq",
862
+ "plotMGaverageAGD",
863
+ "plotMGaverageAGDvsThickness",
864
+ "plotMGAcquisitionAGDOverTime",
865
+ "plotMGAGDvsThickness",
866
+ "plotMGmAsvsThickness",
867
+ "plotMGkVpvsThickness",
868
+ "plotMGStandardAcquisitionFreq",
869
+ "plotMGStandardAverageAGD",
870
+ "plotMGStandardAverageAGDvsThickness",
871
+ "plotMGStandardAcquisitionAGDOverTime",
872
+ "plotMGStandardAGDvsThickness",
873
+ "plotMGStandardmAsvsThickness",
874
+ "plotMGStandardkVpvsThickness",
875
+ "plotMGStudyPerDayAndHour",
876
+ "plotMGStandardStudyPerDayAndHour",
877
+ "plotMGOverTimePeriod",
878
+ "plotMGInitialSortingChoice",
879
+ ]
880
+
881
+
882
+ class DXChartOptionsDisplayForm(forms.Form):
883
+ """Form for DX chart display options"""
884
+
885
+ plotDXAcquisitionFreq = forms.BooleanField(
886
+ label=_("Acquisition frequency"), required=False
887
+ )
888
+ plotDXAcquisitionMeanDAP = forms.BooleanField(
889
+ label=_("Acquisition DAP"), required=False
890
+ )
891
+ plotDXAcquisitionMeanmAs = forms.BooleanField(
892
+ label=_("Acquisition mAs"), required=False
893
+ )
894
+ plotDXAcquisitionMeankVp = forms.BooleanField(
895
+ label=_("Acquisition kVp"), required=False
896
+ )
897
+ plotDXAcquisitionMeanDAPOverTime = forms.BooleanField(
898
+ label=_("Acquisition DAP over time"), required=False
899
+ )
900
+ plotDXAcquisitionMeanmAsOverTime = forms.BooleanField(
901
+ label=_("Acquisition mAs over time"), required=False
902
+ )
903
+ plotDXAcquisitionMeankVpOverTime = forms.BooleanField(
904
+ label=_("Acquisition kVp over time"), required=False
905
+ )
906
+ plotDXAcquisitionDAPvsMass = forms.BooleanField(
907
+ label=_("Acquisition DAP vs mass"), required=False
908
+ )
909
+ plotDXStudyFreq = forms.BooleanField(label=_("Study frequency"), required=False)
910
+ plotDXStudyMeanDAP = forms.BooleanField(label=_("Study DAP"), required=False)
911
+ plotDXStudyDAPvsMass = forms.BooleanField(
912
+ label=_("Study DAP vs mass"), required=False
913
+ )
914
+ plotDXStudyPerDayAndHour = forms.BooleanField(
915
+ label=_("Study workload"), required=False
916
+ )
917
+ plotDXRequestFreq = forms.BooleanField(
918
+ label=_("Requested procedure frequency"), required=False
919
+ )
920
+ plotDXRequestMeanDAP = forms.BooleanField(
921
+ label=_("Requested procedure DAP"), required=False
922
+ )
923
+ plotDXRequestDAPvsMass = forms.BooleanField(
924
+ label=_("Requested procedure DAP vs mass"), required=False
925
+ )
926
+ plotDXAcquisitionMeanDAPOverTimePeriod = forms.ChoiceField(
927
+ label=_("Time period"), choices=CommonVariables.TIME_PERIOD, required=False
928
+ )
929
+ plotDXInitialSortingChoice = forms.ChoiceField(
930
+ label=_("Default chart sorting"),
931
+ choices=CommonVariables.SORTING_CHOICES,
932
+ required=False,
933
+ )
934
+
935
+
936
+ class DXChartOptionsDisplayFormIncStandard(DXChartOptionsDisplayForm):
937
+ plotDXStandardAcquisitionFreq = forms.BooleanField(
938
+ label="Standard acquisition name frequency", required=False
939
+ )
940
+ plotDXStandardAcquisitionMeanDAP = forms.BooleanField(
941
+ label="Standard acquisition name DAP", required=False
942
+ )
943
+ plotDXStandardAcquisitionMeanmAs = forms.BooleanField(
944
+ label="Standard acquisition name mAs", required=False
945
+ )
946
+ plotDXStandardAcquisitionMeankVp = forms.BooleanField(
947
+ label="Standard acquisition name kVp", required=False
948
+ )
949
+ plotDXStandardAcquisitionMeanDAPOverTime = forms.BooleanField(
950
+ label="Standard acquisition name DAP over time", required=False
951
+ )
952
+ plotDXStandardAcquisitionMeanmAsOverTime = forms.BooleanField(
953
+ label="Standard acquisition name mAs over time", required=False
954
+ )
955
+ plotDXStandardAcquisitionMeankVpOverTime = forms.BooleanField(
956
+ label="Standard acquisition name kVp over time", required=False
957
+ )
958
+ plotDXStandardAcquisitionDAPvsMass = forms.BooleanField(
959
+ label="Standard acquisition name DAP vs mass", required=False
960
+ )
961
+ plotDXStandardStudyFreq = forms.BooleanField(
962
+ label="Standard study name frequency", required=False
963
+ )
964
+ plotDXStandardStudyMeanDAP = forms.BooleanField(
965
+ label="Standard study name DAP", required=False
966
+ )
967
+ plotDXStandardStudyDAPvsMass = forms.BooleanField(
968
+ label="Standard study name DAP vs mass", required=False
969
+ )
970
+ plotDXStandardStudyPerDayAndHour = forms.BooleanField(
971
+ label="Standard study name workload", required=False
972
+ )
973
+
974
+ field_order = [
975
+ "plotDXAcquisitionFreq",
976
+ "plotDXAcquisitionMeanDAP",
977
+ "plotDXAcquisitionMeanmAs",
978
+ "plotDXAcquisitionMeankVp",
979
+ "plotDXAcquisitionMeanDAPOverTime",
980
+ "plotDXAcquisitionMeanmAsOverTime",
981
+ "plotDXAcquisitionMeankVpOverTime",
982
+ "plotDXAcquisitionDAPvsMass",
983
+ "plotDXStandardAcquisitionFreq",
984
+ "plotDXStandardAcquisitionMeanDAP",
985
+ "plotDXStandardAcquisitionMeanmAs",
986
+ "plotDXStandardAcquisitionMeankVp",
987
+ "plotDXStandardAcquisitionMeanDAPOverTime",
988
+ "plotDXStandardAcquisitionMeanmAsOverTime",
989
+ "plotDXStandardAcquisitionMeankVpOverTime",
990
+ "plotDXStandardAcquisitionDAPvsMass",
991
+ "plotDXStudyFreq",
992
+ "plotDXStudyMeanDAP",
993
+ "plotDXStudyDAPvsMass",
994
+ "plotDXStudyPerDayAndHour",
995
+ "plotDXRequestFreq",
996
+ "plotDXRequestMeanDAP",
997
+ "plotDXRequestDAPvsMass",
998
+ "plotDXStandardStudyFreq",
999
+ "plotDXStandardStudyMeanDAP",
1000
+ "plotDXStandardStudyDAPvsMass",
1001
+ "plotDXStandardStudyPerDayAndHour",
1002
+ "plotDXAcquisitionMeanDAPOverTimePeriod",
1003
+ "plotDXInitialSortingChoice",
1004
+ ]
1005
+
1006
+
1007
+ class CTChartOptionsDisplayForm(forms.Form):
1008
+ """Form for CT chart display options"""
1009
+
1010
+ plotCTAcquisitionFreq = forms.BooleanField(
1011
+ label=_("Acquisition frequency"), required=False
1012
+ )
1013
+ plotCTAcquisitionMeanDLP = forms.BooleanField(
1014
+ label=_("Acquisition DLP"), required=False
1015
+ )
1016
+ plotCTAcquisitionMeanCTDI = forms.BooleanField(
1017
+ label=mark_safe(_("Acquisition CTDI<sub>vol</sub>")), required=False # nosec
1018
+ )
1019
+ plotCTAcquisitionDLPOverTime = forms.BooleanField(
1020
+ label=_("Acquisition DLP over time"), required=False
1021
+ )
1022
+ plotCTAcquisitionCTDIOverTime = forms.BooleanField(
1023
+ label=mark_safe(_("Acquisition CTDI<sub>vol</sub> over time")), # nosec
1024
+ required=False,
1025
+ )
1026
+ plotCTAcquisitionDLPvsMass = forms.BooleanField(
1027
+ label=_("Acquisition DLP vs mass"), required=False
1028
+ )
1029
+ plotCTAcquisitionCTDIvsMass = forms.BooleanField(
1030
+ label=_("Acquisition CTDI vs mass"), required=False
1031
+ )
1032
+ plotCTAcquisitionTypes = forms.MultipleChoiceField(
1033
+ label=mark_safe( # nosec
1034
+ _(
1035
+ "Acquisition types to include<br/>in acquisition-level chart<br/>calculations"
1036
+ )
1037
+ ),
1038
+ choices=CommonVariables.CT_ACQUISITION_TYPES,
1039
+ required=False,
1040
+ widget=forms.CheckboxSelectMultiple(attrs={"class": "CheckboxSelectMultiple"}),
1041
+ )
1042
+ plotCTStudyFreq = forms.BooleanField(label=_("Study frequency"), required=False)
1043
+ plotCTStudyMeanDLP = forms.BooleanField(label=_("Study DLP"), required=False)
1044
+ plotCTStudyMeanCTDI = forms.BooleanField(
1045
+ label=mark_safe(_("Study CTDI<sub>vol</sub>")), required=False # nosec
1046
+ )
1047
+ plotCTStudyNumEvents = forms.BooleanField(label=_("Study events"), required=False)
1048
+ plotCTStudyMeanDLPOverTime = forms.BooleanField(
1049
+ label=_("Study DLP over time"), required=False
1050
+ )
1051
+ plotCTStudyPerDayAndHour = forms.BooleanField(
1052
+ label=_("Study workload"), required=False
1053
+ )
1054
+ plotCTRequestFreq = forms.BooleanField(
1055
+ label=_("Requested procedure frequency"), required=False
1056
+ )
1057
+ plotCTRequestMeanDLP = forms.BooleanField(
1058
+ label=_("Requested procedure DLP"), required=False
1059
+ )
1060
+ plotCTRequestNumEvents = forms.BooleanField(
1061
+ label=_("Requested procedure events"), required=False
1062
+ )
1063
+ plotCTRequestDLPOverTime = forms.BooleanField(
1064
+ label=_("Requested procedure DLP over time"), required=False
1065
+ )
1066
+ plotCTOverTimePeriod = forms.ChoiceField(
1067
+ label=_("Time period"), choices=CommonVariables.TIME_PERIOD, required=False
1068
+ )
1069
+ plotCTInitialSortingChoice = forms.ChoiceField(
1070
+ label=_("Chart sorting"),
1071
+ choices=CommonVariables.SORTING_CHOICES,
1072
+ required=False,
1073
+ )
1074
+
1075
+
1076
+ class CTChartOptionsDisplayFormIncStandard(CTChartOptionsDisplayForm):
1077
+ plotCTStandardAcquisitionFreq = forms.BooleanField(
1078
+ label="Standard acquisition name frequency", required=False
1079
+ )
1080
+ plotCTStandardAcquisitionMeanDLP = forms.BooleanField(
1081
+ label="Standard acquisition DLP", required=False
1082
+ )
1083
+ plotCTStandardAcquisitionMeanCTDI = forms.BooleanField(
1084
+ label=mark_safe("Standard acquisition CTDI<sub>vol</sub>"), # nosec
1085
+ required=False,
1086
+ )
1087
+ plotCTStandardAcquisitionDLPOverTime = forms.BooleanField(
1088
+ label="Standard acquisition name DLP over time", required=False
1089
+ )
1090
+ plotCTStandardAcquisitionCTDIOverTime = forms.BooleanField(
1091
+ label=mark_safe( # nosec
1092
+ "Standard acquisition name CTDI<sub>vol</sub> over time"
1093
+ ),
1094
+ required=False,
1095
+ )
1096
+ plotCTStandardAcquisitionCTDIvsMass = forms.BooleanField(
1097
+ label=mark_safe( # nosec
1098
+ "Standard acquisition name CTDI<sub>vol</sub> vs mass"
1099
+ ),
1100
+ required=False,
1101
+ )
1102
+ plotCTStandardAcquisitionDLPvsMass = forms.BooleanField(
1103
+ label="Standard acquisition name DLP vs mass", required=False
1104
+ )
1105
+
1106
+ plotCTStandardStudyMeanDLP = forms.BooleanField(
1107
+ label="Standard study DLP", required=False
1108
+ )
1109
+ plotCTStandardStudyNumEvents = forms.BooleanField(
1110
+ label="Standard study events", required=False
1111
+ )
1112
+ plotCTStandardStudyFreq = forms.BooleanField(
1113
+ label="Standard study frequency", required=False
1114
+ )
1115
+ plotCTStandardStudyMeanDLPOverTime = forms.BooleanField(
1116
+ label="Standard study DLP over time", required=False
1117
+ )
1118
+ plotCTStandardStudyPerDayAndHour = forms.BooleanField(
1119
+ label="Standard study workload", required=False
1120
+ )
1121
+
1122
+ field_order = [
1123
+ "plotCTAcquisitionFreq",
1124
+ "plotCTAcquisitionMeanDLP",
1125
+ "plotCTAcquisitionMeanCTDI",
1126
+ "plotCTAcquisitionDLPOverTime",
1127
+ "plotCTAcquisitionCTDIOverTime",
1128
+ "plotCTAcquisitionDLPvsMass",
1129
+ "plotCTAcquisitionCTDIvsMass",
1130
+ "plotCTAcquisitionTypes",
1131
+ "plotCTStandardAcquisitionFreq",
1132
+ "plotCTStandardAcquisitionMeanDLP",
1133
+ "plotCTStandardAcquisitionMeanCTDI",
1134
+ "plotCTStandardAcquisitionDLPOverTime",
1135
+ "plotCTStandardAcquisitionCTDIOverTime",
1136
+ "plotCTStandardAcquisitionDLPvsMass",
1137
+ "plotCTStandardAcquisitionCTDIvsMass",
1138
+ "plotCTStudyFreq",
1139
+ "plotCTStudyMeanDLP",
1140
+ "plotCTStudyMeanCTDI",
1141
+ "plotCTStudyNumEvents",
1142
+ "plotCTStudyMeanDLPOverTime",
1143
+ "plotCTStudyPerDayAndHour",
1144
+ "plotCTRequestFreq",
1145
+ "plotCTRequestMeanDLP",
1146
+ "plotCTRequestNumEvents",
1147
+ "plotCTRequestDLPOverTime",
1148
+ "plotCTStandardStudyFreq",
1149
+ "plotCTStandardStudyMeanDLP",
1150
+ "plotCTStandardStudyNumEvents",
1151
+ "plotCTStandardStudyMeanDLPOverTime",
1152
+ "plotCTStandardStudyPerDayAndHour",
1153
+ "plotCTOverTimePeriod",
1154
+ "plotCTInitialSortingChoice",
1155
+ ]
1156
+
1157
+
1158
+ class GeneralChartOptionsDisplayForm(forms.Form):
1159
+ """Form for general chart display options"""
1160
+
1161
+ plotCharts = forms.BooleanField(label=_("Plot charts?"), required=False)
1162
+ plotAverageChoice = forms.MultipleChoiceField(
1163
+ label=_("Average plots"),
1164
+ choices=CommonVariables.AVERAGES,
1165
+ required=False,
1166
+ widget=forms.CheckboxSelectMultiple(attrs={"class": "CheckboxSelectMultiple"}),
1167
+ )
1168
+ plotInitialSortingDirection = forms.ChoiceField(
1169
+ label=_("Sorting direction"),
1170
+ choices=CommonVariables.SORTING_DIRECTION,
1171
+ required=False,
1172
+ )
1173
+ plotSeriesPerSystem = forms.BooleanField(
1174
+ label=_("Plot a series per system"), required=False
1175
+ )
1176
+ plotHistograms = forms.BooleanField(
1177
+ label=_("Calculate histogram data"), required=False
1178
+ )
1179
+ plotHistogramBins = forms.IntegerField(
1180
+ label=_("Number of histogram bins"), min_value=2, max_value=40, required=False
1181
+ )
1182
+ plotHistogramGlobalBins = forms.BooleanField(
1183
+ label=_("Fixed histogram bins across subplots"), required=False
1184
+ )
1185
+ plotCaseInsensitiveCategories = forms.BooleanField(
1186
+ label=_("Case-insensitive categories"), required=False
1187
+ )
1188
+ plotRemoveCategoryWhitespacePadding = forms.BooleanField(
1189
+ label=_("Remove category whitespace padding"), required=False
1190
+ )
1191
+ plotLabelCharWrap = forms.IntegerField(
1192
+ label=_("Chart label character wrap length"),
1193
+ min_value=10,
1194
+ max_value=500,
1195
+ required=False,
1196
+ )
1197
+ plotGrouping = forms.ChoiceField(
1198
+ label=_("Chart grouping"),
1199
+ choices=CommonVariables.CHART_GROUPING,
1200
+ required=False,
1201
+ )
1202
+ plotThemeChoice = forms.ChoiceField(
1203
+ label=_("Chart theme"), choices=CommonVariables.CHART_THEMES, required=False
1204
+ )
1205
+ plotColourMapChoice = forms.ChoiceField(
1206
+ label=_("Colour map choice"),
1207
+ choices=CommonVariables.CHART_COLOUR_MAPS,
1208
+ required=False,
1209
+ widget=forms.RadioSelect(attrs={"id": "value"}),
1210
+ )
1211
+ plotFacetColWrapVal = forms.IntegerField(
1212
+ label=_("Number of sub-charts per row"),
1213
+ min_value=1,
1214
+ max_value=10,
1215
+ required=False,
1216
+ )
1217
+
1218
+
1219
+ class UpdateDisplayNamesForm(forms.Form):
1220
+ display_names = forms.CharField()
1221
+
1222
+
1223
+ class RFHighDoseFluoroAlertsForm(forms.ModelForm):
1224
+ """Form for displaying and changing fluoroscopy high dose alert settings"""
1225
+
1226
+ def __init__(self, *args, **kwargs):
1227
+ from crispy_forms.layout import Button
1228
+
1229
+ super(RFHighDoseFluoroAlertsForm, self).__init__(*args, **kwargs)
1230
+ self.helper = FormHelper(self)
1231
+ self.helper.form_class = "form-horizontal"
1232
+
1233
+ # If HighDoseMetricAlertSettings.changed_accum_dose_delta_weeks is True then the summed DAP and dose at RP
1234
+ # values have not yet been recalculated - display the recalculate button on the form.
1235
+ if self.instance.changed_accum_dose_delta_weeks:
1236
+ self.helper.add_input(
1237
+ Button(
1238
+ "recalc_all_summed_data",
1239
+ "Recalculate all summed data",
1240
+ css_class="btn btn-warning",
1241
+ )
1242
+ )
1243
+
1244
+ # If there is nothing in self.data and accum_dose_delta_weeks is in self.changed_data then the user must have
1245
+ # changed the accum_dose_delta_weeks value: set the changed_accum_dose_delta_weeks flag to True. This updates
1246
+ # the HighDoseMetricAlertSettings.changed_accum_dose_delta_weeks to True.
1247
+ if len(self.data):
1248
+ if self.has_changed():
1249
+ if "accum_dose_delta_weeks" in self.changed_data:
1250
+ self.instance.changed_accum_dose_delta_weeks = True
1251
+ self.save()
1252
+ self.helper.layout = Layout(
1253
+ Div(
1254
+ "alert_total_dap_rf",
1255
+ "alert_total_rp_dose_rf",
1256
+ "alert_skindose",
1257
+ "accum_dose_delta_weeks",
1258
+ "show_accum_dose_over_delta_weeks",
1259
+ "calc_accum_dose_over_delta_weeks_on_import",
1260
+ "send_high_dose_metric_alert_emails_ref",
1261
+ "send_high_dose_metric_alert_emails_skin",
1262
+ ),
1263
+ FormActions(Submit("submit", "Submit")),
1264
+ )
1265
+
1266
+ class Meta(object):
1267
+ model = HighDoseMetricAlertSettings
1268
+ fields = [
1269
+ "alert_total_dap_rf",
1270
+ "alert_total_rp_dose_rf",
1271
+ "alert_skindose",
1272
+ "accum_dose_delta_weeks",
1273
+ "show_accum_dose_over_delta_weeks",
1274
+ "calc_accum_dose_over_delta_weeks_on_import",
1275
+ "send_high_dose_metric_alert_emails_ref",
1276
+ "send_high_dose_metric_alert_emails_skin",
1277
+ ]
1278
+
1279
+
1280
+ class HomepageOptionsForm(forms.Form):
1281
+ """Form for displaying and changing the home page options"""
1282
+
1283
+ dayDeltaA = forms.IntegerField(
1284
+ label=_("Primary time period to sum studies (days)"), required=False
1285
+ )
1286
+ dayDeltaB = forms.IntegerField(
1287
+ label=_("Secondary time period to sum studies (days)"), required=False
1288
+ )
1289
+ enable_workload_stats = forms.BooleanField(
1290
+ label=_("Enable calculation and display of workload stats on home page?"),
1291
+ required=False,
1292
+ )
1293
+
1294
+
1295
+ class MergeOnDeviceObserverUIDForm(forms.Form):
1296
+ """Form for displaying and changing the option for merging on Device Observer UID"""
1297
+
1298
+ match_on_device_observer_uid = forms.BooleanField(
1299
+ label=_(
1300
+ "Set Display Name and Modality type if Device Observer UID is matching"
1301
+ ),
1302
+ required=False,
1303
+ )
1304
+
1305
+
1306
+ class DicomQueryForm(forms.Form):
1307
+ """Form for launching DICOM Query"""
1308
+
1309
+ from datetime import date
1310
+
1311
+ MODALITIES = (
1312
+ ("CT", _("CT")),
1313
+ ("FL", _("Fluoroscopy (XA and RF)")),
1314
+ ("DX", _("DX, including CR")),
1315
+ ("MG", _("Mammography")),
1316
+ ("NM", _("Nuclear Medicine")),
1317
+ )
1318
+
1319
+ remote_host_field = forms.ChoiceField(
1320
+ choices=[], widget=forms.Select(attrs={"class": "form-control"})
1321
+ )
1322
+ store_scp_field = forms.ChoiceField(
1323
+ choices=[], widget=forms.Select(attrs={"class": "form-control"})
1324
+ )
1325
+ date_from_field = forms.DateField(
1326
+ label=_("Date from"),
1327
+ widget=forms.DateInput(attrs={"class": "form-control datepicker"}),
1328
+ required=False,
1329
+ initial=date.today().isoformat(),
1330
+ help_text=_("Format yyyy-mm-dd, restrict as much as possible for best results"),
1331
+ )
1332
+ date_until_field = forms.DateField(
1333
+ label=_("Date until"),
1334
+ widget=forms.DateInput(attrs={"class": "form-control datepicker"}),
1335
+ required=False,
1336
+ help_text=_("Format yyyy-mm-dd, restrict as much as possible for best results"),
1337
+ )
1338
+ modality_field = forms.MultipleChoiceField(
1339
+ choices=MODALITIES,
1340
+ widget=forms.CheckboxSelectMultiple(attrs={"checked": ""}),
1341
+ required=False,
1342
+ help_text=(
1343
+ _(
1344
+ "At least one modality must be ticked - if SR only is ticked (Advanced) these "
1345
+ "modalities will be ignored"
1346
+ )
1347
+ ),
1348
+ )
1349
+ inc_sr_field = forms.BooleanField(
1350
+ label=_("Include SR only studies?"),
1351
+ required=False,
1352
+ initial=False,
1353
+ help_text=_(
1354
+ "Only use with stores containing only RDSRs, with no accompanying images"
1355
+ ),
1356
+ )
1357
+ duplicates_field = forms.BooleanField(
1358
+ label=_("Ignore studies already in the database?"),
1359
+ required=False,
1360
+ initial=True,
1361
+ help_text=_(
1362
+ "Objects that have already been processed won't be imported, "
1363
+ "so there isn't any point getting them!"
1364
+ ),
1365
+ )
1366
+ desc_exclude_field = forms.CharField(
1367
+ required=False,
1368
+ label=_("Exclude studies with these terms in the study description:"),
1369
+ help_text=_("Comma separated list of terms"),
1370
+ )
1371
+ desc_include_field = forms.CharField(
1372
+ required=False,
1373
+ label=_("Only keep studies with these terms in the study description:"),
1374
+ help_text=_("Comma separated list of terms"),
1375
+ )
1376
+ stationname_exclude_field = forms.CharField(
1377
+ required=False,
1378
+ label=_("Exclude studies or series with these terms in the station name:"),
1379
+ help_text=_(
1380
+ "Comma separated list of terms, tested at series level — see Advanced"
1381
+ ),
1382
+ )
1383
+ stationname_include_field = forms.CharField(
1384
+ required=False,
1385
+ label=_("Only keep studies or series with these terms in the station name:"),
1386
+ help_text=_(
1387
+ "Comma separated list of terms, tested at series level — see Advanced"
1388
+ ),
1389
+ )
1390
+ get_toshiba_images_field = forms.BooleanField(
1391
+ label=_("Attempt to get Toshiba dose images"),
1392
+ required=False,
1393
+ help_text=_(
1394
+ "Only applicable if using Toshiba RDSR generator extension, see docs"
1395
+ ),
1396
+ )
1397
+ get_empty_sr_field = forms.BooleanField(
1398
+ label=_("Get SR series that return nothing at image level query"),
1399
+ help_text=_("Only use if suggested in qrscu log, see docs"),
1400
+ required=False,
1401
+ )
1402
+ stationname_study_level_field = forms.BooleanField(
1403
+ label=_("Check station name include/exclude at study level"),
1404
+ help_text=_("Default from v1.0 is to check at series level only"),
1405
+ required=False,
1406
+ )
1407
+
1408
+ def __init__(self, *args, **kwargs):
1409
+ super(DicomQueryForm, self).__init__(*args, **kwargs)
1410
+
1411
+ self.fields["remote_host_field"].choices = [
1412
+ (x.pk, x.name) for x in DicomRemoteQR.objects.all()
1413
+ ]
1414
+ self.fields["store_scp_field"].choices = [
1415
+ (x.pk, x.name) for x in DicomStoreSCP.objects.all()
1416
+ ]
1417
+ self.helper = FormHelper(self)
1418
+ self.helper.form_id = "post-form"
1419
+ self.helper.form_method = "post"
1420
+ self.helper.form_action = "queryprocess"
1421
+ self.helper.add_input(Submit("submit", "Submit"))
1422
+ self.helper.layout = Layout(
1423
+ Div(
1424
+ Div(
1425
+ Div("remote_host_field", css_class="col-md-6"),
1426
+ Div("store_scp_field", css_class="col-md-6"),
1427
+ ),
1428
+ InlineCheckboxes("modality_field"),
1429
+ Div(
1430
+ Div("date_from_field", css_class="col-md-6"),
1431
+ Div("date_until_field", css_class="col-md-6"),
1432
+ ),
1433
+ "desc_exclude_field",
1434
+ "desc_include_field",
1435
+ "stationname_exclude_field",
1436
+ "stationname_include_field",
1437
+ Accordion(
1438
+ AccordionGroup(
1439
+ "Advanced",
1440
+ "get_toshiba_images_field",
1441
+ "duplicates_field",
1442
+ "inc_sr_field",
1443
+ "get_empty_sr_field",
1444
+ "stationname_study_level_field",
1445
+ active=False,
1446
+ )
1447
+ ),
1448
+ )
1449
+ )
1450
+
1451
+ def clean(self):
1452
+ """
1453
+ Validate the form data to clear modality selections if sr_only is selected.
1454
+ :return: Form with modalities _or_ sr_only selected
1455
+ """
1456
+ qr_logger = logging.getLogger("remapp.netdicom.qrscu")
1457
+
1458
+ cleaned_data = super(DicomQueryForm, self).clean()
1459
+ mods = cleaned_data.get("modality_field")
1460
+ inc_sr = cleaned_data.get("inc_sr_field")
1461
+ qr_logger.debug("Form mods are {0}, inc_sr is {1}".format(mods, inc_sr))
1462
+ qr_logger.debug("All form modes are {0}".format(cleaned_data))
1463
+ if inc_sr:
1464
+ self.cleaned_data["modality_field"] = None
1465
+ elif not mods:
1466
+ raise forms.ValidationError(
1467
+ "You must select at least one modality (or Advanced SR Only)"
1468
+ )
1469
+ return cleaned_data
1470
+
1471
+
1472
+ class DicomDeleteSettingsForm(forms.ModelForm):
1473
+ """Form for configuring whether DICOM objects are stored or deleted once processed"""
1474
+
1475
+ def __init__(self, *args, **kwargs):
1476
+ super(DicomDeleteSettingsForm, self).__init__(*args, **kwargs)
1477
+ self.helper = FormHelper(self)
1478
+ self.helper.form_class = "form-horizontal"
1479
+ self.helper.label_class = "col-lg-2"
1480
+ self.helper.field_class = "col-lg-8"
1481
+ self.helper.layout = Layout(
1482
+ Div(
1483
+ HTML(
1484
+ """
1485
+ <h4>Do you want objects that we can't do anything with to be deleted?</h4>
1486
+ """
1487
+ ),
1488
+ "del_no_match",
1489
+ HTML(
1490
+ """
1491
+ <h4>The remaining choices are for DICOM objects we have processed and attempted to import to the
1492
+ database:</h4>
1493
+ """
1494
+ ),
1495
+ "del_rdsr",
1496
+ "del_mg_im",
1497
+ "del_dx_im",
1498
+ "del_ct_phil",
1499
+ "del_nm_im",
1500
+ ),
1501
+ FormActions(Submit("submit", "Submit")),
1502
+ Div(
1503
+ HTML(
1504
+ """
1505
+ <div class="col-lg-4 col-lg-offset-2">
1506
+ <a href='"""
1507
+ + reverse("dicom_summary")
1508
+ + """#delete' role="button" class="btn btn-default">
1509
+ Cancel and return to the DICOM configuration and DICOM object delete summary page
1510
+ </a>
1511
+ </div>
1512
+ """
1513
+ )
1514
+ ),
1515
+ )
1516
+
1517
+ class Meta(object):
1518
+ model = DicomDeleteSettings
1519
+ fields = [
1520
+ "del_no_match",
1521
+ "del_rdsr",
1522
+ "del_mg_im",
1523
+ "del_dx_im",
1524
+ "del_ct_phil",
1525
+ "del_nm_im",
1526
+ ]
1527
+
1528
+
1529
+ class DicomQRForm(forms.ModelForm):
1530
+ """Form for configuring remote Query Retrieve nodes"""
1531
+
1532
+ def __init__(self, *args, **kwargs):
1533
+ super(DicomQRForm, self).__init__(*args, **kwargs)
1534
+ self.helper = FormHelper(self)
1535
+ self.helper.form_class = "form-horizontal"
1536
+ self.helper.label_class = "col-md-8"
1537
+ self.helper.field_class = "col-md-4"
1538
+ self.helper.layout = Layout(
1539
+ Div("name", "aetitle", "callingaet", "port", "ip", "hostname"),
1540
+ Accordion(
1541
+ AccordionGroup(
1542
+ "Non-standard configuration options",
1543
+ Div(
1544
+ HTML(
1545
+ """
1546
+ <p>
1547
+ Some PACS systems (like Impax 6.6) need modality at study level for correct filtering.
1548
+ Others will return no results if modality is included at study level. See
1549
+ <a href="https://docs.openrem.org/en/{{ admin.docsversion }}/netdicom-qr-config.html"
1550
+ target="_blank" data-toggle="tooltip"
1551
+ title="DICOM query-retrieve node config documentation - opens in a new tab">
1552
+ DICOM query-retrieve node config documentation
1553
+ </a>
1554
+ </p>
1555
+ """
1556
+ )
1557
+ ),
1558
+ PrependedText(
1559
+ "use_modality_tag", ""
1560
+ ), # Trick to force label to join the other labels,
1561
+ # otherwise sits to right
1562
+ active=False,
1563
+ )
1564
+ ),
1565
+ FormActions(Submit("submit", "Submit")),
1566
+ Div(
1567
+ HTML(
1568
+ """
1569
+ <div class="col-lg-4 col-lg-offset-4">
1570
+ <a href='"""
1571
+ + reverse("dicom_summary")
1572
+ + """' role="button" class="btn btn-default">
1573
+ Cancel and return to DICOM configuration summary page
1574
+ </a>
1575
+ </div>
1576
+ """
1577
+ )
1578
+ ),
1579
+ )
1580
+
1581
+ class Meta(object):
1582
+ model = DicomRemoteQR
1583
+ fields = [
1584
+ "name",
1585
+ "aetitle",
1586
+ "callingaet",
1587
+ "port",
1588
+ "ip",
1589
+ "hostname",
1590
+ "use_modality_tag",
1591
+ ]
1592
+
1593
+
1594
+ class DicomStoreForm(forms.ModelForm):
1595
+ """Form for configuring local Store nodes"""
1596
+
1597
+ def __init__(self, *args, **kwargs):
1598
+ super(DicomStoreForm, self).__init__(*args, **kwargs)
1599
+ self.helper = FormHelper(self)
1600
+ self.helper.form_class = "form-horizontal"
1601
+ self.helper.label_class = "col-md-8"
1602
+ self.helper.field_class = "col-md-4"
1603
+ if not settings.DOCKER_INSTALL:
1604
+ self.helper.layout = Layout(
1605
+ Div("name", "aetitle", "peer", "port"),
1606
+ FormActions(Submit("submit", "Submit")),
1607
+ Div(
1608
+ HTML(
1609
+ """
1610
+ <div class="col-lg-4 col-lg-offset-4">
1611
+ <a href='"""
1612
+ + reverse("dicom_summary")
1613
+ + """' role="button" class="btn btn-default">
1614
+ Cancel and return to DICOM configuration summary page
1615
+ </a>
1616
+ </div>
1617
+ """
1618
+ )
1619
+ ),
1620
+ )
1621
+ else:
1622
+ self.helper.layout = Layout(
1623
+ Div("name", "aetitle", "peer", "port"),
1624
+ FormActions(Submit("submit", "Submit")),
1625
+ Div(
1626
+ HTML(
1627
+ """
1628
+ <div class="col-lg-4 col-lg-offset-4">
1629
+ <a href='"""
1630
+ + reverse("dicom_summary")
1631
+ + """' role="button" class="btn btn-default">
1632
+ Cancel and return to DICOM configuration summary page
1633
+ </a>
1634
+ </div>
1635
+ """
1636
+ )
1637
+ ),
1638
+ )
1639
+
1640
+ class Meta(object):
1641
+ model = DicomStoreSCP
1642
+ fields = ["name", "aetitle", "peer", "port"]
1643
+ labels = {
1644
+ "peer": "Peer: Set this to localhost",
1645
+ "port": "Port: port 104 is standard for DICOM but ports higher than 1024 require fewer admin rights",
1646
+ }
1647
+ if settings.DOCKER_INSTALL:
1648
+ labels["peer"] = "Docker container name: initial default is orthanc_1"
1649
+ labels["port"] = (
1650
+ "Port: set to the same as the DICOM_PORT setting in docker-compose.yml"
1651
+ )
1652
+
1653
+
1654
+ class StandardNameFormBase(forms.ModelForm):
1655
+ """For configuring standard names for study description, requested procedure, procedure and acquisition name."""
1656
+
1657
+ class Meta(object):
1658
+ model = StandardNames
1659
+ fields = [
1660
+ "standard_name",
1661
+ "modality",
1662
+ "study_description",
1663
+ "requested_procedure_code_meaning",
1664
+ "procedure_code_meaning",
1665
+ "acquisition_protocol",
1666
+ ]
1667
+ widgets = {
1668
+ "standard_name": forms.TextInput,
1669
+ "modality": forms.HiddenInput,
1670
+ }
1671
+
1672
+ def clean_study_description(self):
1673
+ if self.cleaned_data["study_description"] == "":
1674
+ return None
1675
+ else:
1676
+ return self.cleaned_data["study_description"]
1677
+
1678
+ def clean_requested_procedure_code_meaning(self):
1679
+ if self.cleaned_data["requested_procedure_code_meaning"] == "":
1680
+ return None
1681
+ else:
1682
+ return self.cleaned_data["requested_procedure_code_meaning"]
1683
+
1684
+ def clean_procedure_code_meaning(self):
1685
+ if self.cleaned_data["procedure_code_meaning"] == "":
1686
+ return None
1687
+ else:
1688
+ return self.cleaned_data["procedure_code_meaning"]
1689
+
1690
+ def clean_acquisition_protocol(self):
1691
+ if self.cleaned_data["acquisition_protocol"] == "":
1692
+ return None
1693
+ else:
1694
+ return self.cleaned_data["acquisition_protocol"]
1695
+
1696
+
1697
+ class StandardNameFormCT(StandardNameFormBase):
1698
+ """Form for configuring standard names for study description, requested procedure, procedure and acquisition name"""
1699
+
1700
+ def __init__(self, *args, **kwargs):
1701
+ super(StandardNameFormCT, self).__init__(*args, **kwargs)
1702
+ self.fields["modality"].initial = "CT"
1703
+
1704
+ all_studies = GeneralStudyModuleAttr.objects.filter(modality_type__iexact="CT")
1705
+
1706
+ field_names = [
1707
+ ("study_description", "Study description"),
1708
+ ("requested_procedure_code_meaning", "Requested procedure name"),
1709
+ ("procedure_code_meaning", "Procedure name"),
1710
+ ]
1711
+
1712
+ for field_name, label_name in field_names:
1713
+ # Exclude items already in the CT standard names entries except for the current value of the field
1714
+ items_to_exclude = (
1715
+ StandardNames.objects.all()
1716
+ .filter(modality="CT")
1717
+ .values(field_name)
1718
+ .exclude(**{field_name: None})
1719
+ )
1720
+ if "standard_name" in self.initial:
1721
+ items_to_exclude = items_to_exclude.exclude(
1722
+ standard_name=self.initial["standard_name"]
1723
+ )
1724
+
1725
+ query = (
1726
+ all_studies.values_list(field_name, flat=True)
1727
+ .exclude(**{field_name + "__in": items_to_exclude})
1728
+ .distinct()
1729
+ .order_by(field_name)
1730
+ )
1731
+ query_choices = [("", "None")] + [(item, item) for item in query]
1732
+
1733
+ initial_choices = (
1734
+ StandardNames.objects.all()
1735
+ .filter(modality="CT")
1736
+ .exclude(**{field_name: None})
1737
+ .order_by(field_name)
1738
+ )
1739
+ if "standard_name" in self.initial:
1740
+ initial_choices = initial_choices.filter(
1741
+ standard_name=self.initial["standard_name"]
1742
+ )
1743
+
1744
+ self.initial[field_name] = list(
1745
+ initial_choices.values_list(field_name, flat=True)
1746
+ )
1747
+
1748
+ self.fields[field_name] = forms.MultipleChoiceField(
1749
+ choices=query_choices,
1750
+ required=False,
1751
+ widget=FilteredSelectMultiple(
1752
+ label_name.lower() + "s", is_stacked=False
1753
+ ),
1754
+ )
1755
+
1756
+ field_name, label_name = ("acquisition_protocol", "Acquisition protocol name")
1757
+ items_to_exclude = (
1758
+ StandardNames.objects.all()
1759
+ .filter(modality="CT")
1760
+ .values(field_name)
1761
+ .exclude(**{field_name: None})
1762
+ )
1763
+ if "standard_name" in self.initial:
1764
+ items_to_exclude = items_to_exclude.exclude(
1765
+ standard_name=self.initial["standard_name"]
1766
+ )
1767
+ query = (
1768
+ CtIrradiationEventData.objects.values_list(field_name, flat=True)
1769
+ .exclude(**{field_name + "__in": items_to_exclude})
1770
+ .distinct()
1771
+ .order_by(field_name)
1772
+ )
1773
+ query_choices = [("", "None")] + [(item, item) for item in query]
1774
+
1775
+ initial_choices = (
1776
+ StandardNames.objects.all()
1777
+ .filter(modality="CT")
1778
+ .exclude(**{field_name: None})
1779
+ .order_by(field_name)
1780
+ )
1781
+ if "standard_name" in self.initial:
1782
+ initial_choices = initial_choices.filter(
1783
+ standard_name=self.initial["standard_name"]
1784
+ )
1785
+
1786
+ self.initial[field_name] = list(
1787
+ initial_choices.values_list(field_name, flat=True)
1788
+ )
1789
+
1790
+ self.fields[field_name] = forms.MultipleChoiceField(
1791
+ choices=query_choices,
1792
+ required=False,
1793
+ widget=FilteredSelectMultiple(label_name.lower() + "s", is_stacked=False),
1794
+ )
1795
+
1796
+ class Media:
1797
+ css = {
1798
+ "all": (
1799
+ os.path.join(settings.BASE_DIR, "/static/admin/css/widgets.css"),
1800
+ ),
1801
+ }
1802
+ js = ("/admin/jsi18n",)
1803
+
1804
+
1805
+ class StandardNameFormDX(StandardNameFormBase):
1806
+ """Form for configuring standard names for study description, requested procedure, procedure and acquisition name"""
1807
+
1808
+ def __init__(self, *args, **kwargs):
1809
+ super(StandardNameFormDX, self).__init__(*args, **kwargs)
1810
+ self.fields["modality"].initial = "DX"
1811
+
1812
+ all_studies = GeneralStudyModuleAttr.objects.filter(
1813
+ Q(modality_type__in=["DX", "CR", "PX"])
1814
+ )
1815
+
1816
+ field_names = [
1817
+ ("study_description", "Study description"),
1818
+ ("requested_procedure_code_meaning", "Requested procedure name"),
1819
+ ("procedure_code_meaning", "Procedure name"),
1820
+ ]
1821
+
1822
+ for field_name, label_name in field_names:
1823
+ # Exclude items already in the DX standard names entries except for the current value of the field
1824
+ items_to_exclude = (
1825
+ StandardNames.objects.all()
1826
+ .filter(modality="DX")
1827
+ .values(field_name)
1828
+ .exclude(**{field_name: None})
1829
+ )
1830
+ if "standard_name" in self.initial:
1831
+ items_to_exclude = items_to_exclude.exclude(
1832
+ standard_name=self.initial["standard_name"]
1833
+ )
1834
+
1835
+ query = (
1836
+ all_studies.values_list(field_name, flat=True)
1837
+ .exclude(**{field_name + "__in": items_to_exclude})
1838
+ .distinct()
1839
+ .order_by(field_name)
1840
+ )
1841
+ query_choices = [("", "None")] + [(item, item) for item in query]
1842
+
1843
+ initial_choices = (
1844
+ StandardNames.objects.all()
1845
+ .filter(modality="DX")
1846
+ .exclude(**{field_name: None})
1847
+ .order_by(field_name)
1848
+ )
1849
+ if "standard_name" in self.initial:
1850
+ initial_choices = initial_choices.filter(
1851
+ standard_name=self.initial["standard_name"]
1852
+ )
1853
+
1854
+ self.initial[field_name] = list(
1855
+ initial_choices.values_list(field_name, flat=True)
1856
+ )
1857
+
1858
+ self.fields[field_name] = forms.MultipleChoiceField(
1859
+ choices=query_choices,
1860
+ required=False,
1861
+ widget=FilteredSelectMultiple(
1862
+ label_name.lower() + "s", is_stacked=False
1863
+ ),
1864
+ )
1865
+
1866
+ q = ["DX", "CR", "PX"]
1867
+ q_criteria = reduce(
1868
+ operator.or_,
1869
+ (
1870
+ Q(
1871
+ projection_xray_radiation_dose__general_study_module_attributes__modality_type__icontains=item
1872
+ )
1873
+ for item in q
1874
+ ),
1875
+ )
1876
+ field_name, label_name = ("acquisition_protocol", "Acquisition protocol name")
1877
+ items_to_exclude = (
1878
+ StandardNames.objects.all()
1879
+ .filter(modality="DX")
1880
+ .values(field_name)
1881
+ .exclude(**{field_name: None})
1882
+ )
1883
+ if "standard_name" in self.initial:
1884
+ items_to_exclude = items_to_exclude.exclude(
1885
+ standard_name=self.initial["standard_name"]
1886
+ )
1887
+ query = (
1888
+ IrradEventXRayData.objects.filter(q_criteria)
1889
+ .values_list(field_name, flat=True)
1890
+ .exclude(**{field_name + "__in": items_to_exclude})
1891
+ .distinct()
1892
+ .order_by(field_name)
1893
+ )
1894
+ query_choices = [("", "None")] + [(item, item) for item in query]
1895
+
1896
+ initial_choices = (
1897
+ StandardNames.objects.all()
1898
+ .filter(modality="DX")
1899
+ .exclude(**{field_name: None})
1900
+ .order_by(field_name)
1901
+ )
1902
+ if "standard_name" in self.initial:
1903
+ initial_choices = initial_choices.filter(
1904
+ standard_name=self.initial["standard_name"]
1905
+ )
1906
+
1907
+ self.initial[field_name] = list(
1908
+ initial_choices.values_list(field_name, flat=True)
1909
+ )
1910
+
1911
+ self.fields[field_name] = forms.MultipleChoiceField(
1912
+ choices=query_choices,
1913
+ required=False,
1914
+ widget=FilteredSelectMultiple(label_name.lower() + "s", is_stacked=False),
1915
+ )
1916
+
1917
+ class Media:
1918
+ css = {
1919
+ "all": (
1920
+ os.path.join(settings.BASE_DIR, "/static/admin/css/widgets.css"),
1921
+ ),
1922
+ }
1923
+ js = ("/admin/jsi18n",)
1924
+
1925
+
1926
+ class StandardNameFormMG(StandardNameFormBase):
1927
+ """Form for configuring standard names for study description, requested procedure, procedure and acquisition name"""
1928
+
1929
+ def __init__(self, *args, **kwargs):
1930
+ super(StandardNameFormMG, self).__init__(*args, **kwargs)
1931
+ self.fields["modality"].initial = "MG"
1932
+
1933
+ all_studies = GeneralStudyModuleAttr.objects.filter(modality_type__iexact="MG")
1934
+
1935
+ field_names = [
1936
+ ("study_description", "Study description"),
1937
+ ("requested_procedure_code_meaning", "Requested procedure name"),
1938
+ ("procedure_code_meaning", "Procedure name"),
1939
+ ]
1940
+
1941
+ for field_name, label_name in field_names:
1942
+ # Exclude items already in the MG standard names entries except for the current value of the field
1943
+ items_to_exclude = (
1944
+ StandardNames.objects.all()
1945
+ .filter(modality="MG")
1946
+ .values(field_name)
1947
+ .exclude(**{field_name: None})
1948
+ )
1949
+ if "standard_name" in self.initial:
1950
+ items_to_exclude = items_to_exclude.exclude(
1951
+ standard_name=self.initial["standard_name"]
1952
+ )
1953
+
1954
+ query = (
1955
+ all_studies.values_list(field_name, flat=True)
1956
+ .exclude(**{field_name + "__in": items_to_exclude})
1957
+ .distinct()
1958
+ .order_by(field_name)
1959
+ )
1960
+ query_choices = [("", "None")] + [(item, item) for item in query]
1961
+
1962
+ initial_choices = (
1963
+ StandardNames.objects.all()
1964
+ .filter(modality="MG")
1965
+ .exclude(**{field_name: None})
1966
+ .order_by(field_name)
1967
+ )
1968
+ if "standard_name" in self.initial:
1969
+ initial_choices = initial_choices.filter(
1970
+ standard_name=self.initial["standard_name"]
1971
+ )
1972
+
1973
+ self.initial[field_name] = list(
1974
+ initial_choices.values_list(field_name, flat=True)
1975
+ )
1976
+
1977
+ self.fields[field_name] = forms.MultipleChoiceField(
1978
+ choices=query_choices,
1979
+ required=False,
1980
+ widget=FilteredSelectMultiple(
1981
+ label_name.lower() + "s", is_stacked=False
1982
+ ),
1983
+ )
1984
+
1985
+ q = ["MG"]
1986
+ q_criteria = reduce(
1987
+ operator.or_,
1988
+ (
1989
+ Q(
1990
+ projection_xray_radiation_dose__general_study_module_attributes__modality_type__icontains=item
1991
+ )
1992
+ for item in q
1993
+ ),
1994
+ )
1995
+ field_name, label_name = ("acquisition_protocol", "Acquisition protocol name")
1996
+ items_to_exclude = (
1997
+ StandardNames.objects.all()
1998
+ .filter(modality="MG")
1999
+ .values(field_name)
2000
+ .exclude(**{field_name: None})
2001
+ )
2002
+ if "standard_name" in self.initial:
2003
+ items_to_exclude = items_to_exclude.exclude(
2004
+ standard_name=self.initial["standard_name"]
2005
+ )
2006
+ query = (
2007
+ IrradEventXRayData.objects.filter(q_criteria)
2008
+ .values_list(field_name, flat=True)
2009
+ .exclude(**{field_name + "__in": items_to_exclude})
2010
+ .distinct()
2011
+ .order_by(field_name)
2012
+ )
2013
+ query_choices = [("", "None")] + [(item, item) for item in query]
2014
+
2015
+ initial_choices = (
2016
+ StandardNames.objects.all()
2017
+ .filter(modality="MG")
2018
+ .exclude(**{field_name: None})
2019
+ .order_by(field_name)
2020
+ )
2021
+ if "standard_name" in self.initial:
2022
+ initial_choices = initial_choices.filter(
2023
+ standard_name=self.initial["standard_name"]
2024
+ )
2025
+
2026
+ self.initial[field_name] = list(
2027
+ initial_choices.values_list(field_name, flat=True)
2028
+ )
2029
+
2030
+ self.fields[field_name] = forms.MultipleChoiceField(
2031
+ choices=query_choices,
2032
+ required=False,
2033
+ widget=FilteredSelectMultiple(label_name.lower() + "s", is_stacked=False),
2034
+ )
2035
+
2036
+ class Media:
2037
+ css = {
2038
+ "all": (
2039
+ os.path.join(settings.BASE_DIR, "/static/admin/css/widgets.css"),
2040
+ ),
2041
+ }
2042
+ js = ("/admin/jsi18n",)
2043
+
2044
+
2045
+ class StandardNameFormRF(StandardNameFormBase):
2046
+ """Form for configuring standard names for study description, requested procedure, procedure and acquisition name"""
2047
+
2048
+ def __init__(self, *args, **kwargs):
2049
+ super(StandardNameFormRF, self).__init__(*args, **kwargs)
2050
+ self.fields["modality"].initial = "RF"
2051
+
2052
+ all_studies = GeneralStudyModuleAttr.objects.filter(modality_type__iexact="RF")
2053
+
2054
+ field_names = [
2055
+ ("study_description", "Study description"),
2056
+ ("requested_procedure_code_meaning", "Requested procedure name"),
2057
+ ("procedure_code_meaning", "Procedure name"),
2058
+ ]
2059
+
2060
+ for field_name, label_name in field_names:
2061
+ # Exclude items already in the RF standard names entries except for the current value of the field
2062
+ items_to_exclude = (
2063
+ StandardNames.objects.all()
2064
+ .filter(modality="RF")
2065
+ .values(field_name)
2066
+ .exclude(**{field_name: None})
2067
+ )
2068
+ if "standard_name" in self.initial:
2069
+ items_to_exclude = items_to_exclude.exclude(
2070
+ standard_name=self.initial["standard_name"]
2071
+ )
2072
+
2073
+ query = (
2074
+ all_studies.values_list(field_name, flat=True)
2075
+ .exclude(**{field_name + "__in": items_to_exclude})
2076
+ .distinct()
2077
+ .order_by(field_name)
2078
+ )
2079
+ query_choices = [("", "None")] + [(item, item) for item in query]
2080
+
2081
+ initial_choices = (
2082
+ StandardNames.objects.all()
2083
+ .filter(modality="RF")
2084
+ .exclude(**{field_name: None})
2085
+ .order_by(field_name)
2086
+ )
2087
+ if "standard_name" in self.initial:
2088
+ initial_choices = initial_choices.filter(
2089
+ standard_name=self.initial["standard_name"]
2090
+ )
2091
+
2092
+ self.initial[field_name] = list(
2093
+ initial_choices.values_list(field_name, flat=True)
2094
+ )
2095
+
2096
+ self.fields[field_name] = forms.MultipleChoiceField(
2097
+ choices=query_choices,
2098
+ required=False,
2099
+ widget=FilteredSelectMultiple(
2100
+ label_name.lower() + "s", is_stacked=False
2101
+ ),
2102
+ )
2103
+
2104
+ q = ["RF"]
2105
+ q_criteria = reduce(
2106
+ operator.or_,
2107
+ (
2108
+ Q(
2109
+ projection_xray_radiation_dose__general_study_module_attributes__modality_type__icontains=item
2110
+ )
2111
+ for item in q
2112
+ ),
2113
+ )
2114
+ field_name, label_name = ("acquisition_protocol", "Acquisition protocol name")
2115
+ items_to_exclude = (
2116
+ StandardNames.objects.all()
2117
+ .filter(modality="RF")
2118
+ .values(field_name)
2119
+ .exclude(**{field_name: None})
2120
+ )
2121
+ if "standard_name" in self.initial:
2122
+ items_to_exclude = items_to_exclude.exclude(
2123
+ standard_name=self.initial["standard_name"]
2124
+ )
2125
+ query = (
2126
+ IrradEventXRayData.objects.filter(q_criteria)
2127
+ .values_list(field_name, flat=True)
2128
+ .exclude(**{field_name + "__in": items_to_exclude})
2129
+ .distinct()
2130
+ .order_by(field_name)
2131
+ )
2132
+ query_choices = [("", "None")] + [(item, item) for item in query]
2133
+
2134
+ initial_choices = (
2135
+ StandardNames.objects.all()
2136
+ .filter(modality="RF")
2137
+ .exclude(**{field_name: None})
2138
+ .order_by(field_name)
2139
+ )
2140
+ if "standard_name" in self.initial:
2141
+ initial_choices = initial_choices.filter(
2142
+ standard_name=self.initial["standard_name"]
2143
+ )
2144
+
2145
+ self.initial[field_name] = list(
2146
+ initial_choices.values_list(field_name, flat=True)
2147
+ )
2148
+
2149
+ self.fields[field_name] = forms.MultipleChoiceField(
2150
+ choices=query_choices,
2151
+ required=False,
2152
+ widget=FilteredSelectMultiple(label_name.lower() + "s", is_stacked=False),
2153
+ )
2154
+
2155
+ class Media:
2156
+ css = {
2157
+ "all": (
2158
+ os.path.join(settings.BASE_DIR, "/static/admin/css/widgets.css"),
2159
+ ),
2160
+ }
2161
+ js = ("/admin/jsi18n",)
2162
+
2163
+
2164
+ class StandardNameSettingsForm(forms.ModelForm):
2165
+ """Form for configuring whether standard names are shown / used"""
2166
+
2167
+ def __init__(self, *args, **kwargs):
2168
+ super(StandardNameSettingsForm, self).__init__(*args, **kwargs)
2169
+ self.helper = FormHelper(self)
2170
+ self.helper.form_class = "form-horizontal"
2171
+ self.helper.layout = Layout(
2172
+ Div("enable_standard_names"),
2173
+ FormActions(Submit("submit", "Submit")),
2174
+ )
2175
+
2176
+ class Meta(object):
2177
+ model = StandardNameSettings
2178
+ fields = ["enable_standard_names"]
2179
+
2180
+
2181
+ class SkinDoseMapCalcSettingsForm(forms.ModelForm):
2182
+ """Form for configuring whether skin dose maps are shown / calculated"""
2183
+
2184
+ def __init__(self, *args, **kwargs):
2185
+ super(SkinDoseMapCalcSettingsForm, self).__init__(*args, **kwargs)
2186
+ self.helper = FormHelper(self)
2187
+ self.helper.form_class = "form-horizontal"
2188
+ self.helper.layout = Layout(
2189
+ Div("enable_skin_dose_maps", "calc_on_import", "allow_safelist_modify"),
2190
+ FormActions(Submit("submit", "Submit")),
2191
+ )
2192
+
2193
+ class Meta(object):
2194
+ model = SkinDoseMapCalcSettings
2195
+ fields = ["enable_skin_dose_maps", "calc_on_import", "allow_safelist_modify"]
2196
+
2197
+
2198
+ class NotPatientNameForm(forms.ModelForm):
2199
+ """Form for configuring not-patient name patterns"""
2200
+
2201
+ def __init__(self, *args, **kwargs):
2202
+ super(NotPatientNameForm, self).__init__(*args, **kwargs)
2203
+ self.helper = FormHelper(self)
2204
+ self.helper.form_class = "form-horizontal"
2205
+ self.helper.label_class = "col-md-8"
2206
+ self.helper.field_class = "col-md-4"
2207
+ self.helper.layout = Layout(
2208
+ Div("not_patient_name"),
2209
+ FormActions(Submit("submit", "Submit")),
2210
+ Div(
2211
+ HTML(
2212
+ """
2213
+ <div class="col-lg-4 col-lg-offset-4">
2214
+ <a href='"""
2215
+ + reverse("not_patient_indicators")
2216
+ + """' role="button" class="btn btn-default">
2217
+ Cancel and return to not-patient indicator summary page
2218
+ </a>
2219
+ </div>
2220
+ """
2221
+ )
2222
+ ),
2223
+ )
2224
+
2225
+ class Meta(object):
2226
+ model = NotPatientIndicatorsName
2227
+ fields = ["not_patient_name"]
2228
+ labels = {"not_patient_name": "pattern for name matching"}
2229
+
2230
+
2231
+ class NotPatientIDForm(forms.ModelForm):
2232
+ """Form for configuring not-patient ID patterns"""
2233
+
2234
+ def __init__(self, *args, **kwargs):
2235
+ super(NotPatientIDForm, self).__init__(*args, **kwargs)
2236
+ self.helper = FormHelper(self)
2237
+ self.helper.form_class = "form-horizontal"
2238
+ self.helper.label_class = "col-md-8"
2239
+ self.helper.field_class = "col-md-4"
2240
+ self.helper.layout = Layout(
2241
+ Div("not_patient_id"),
2242
+ FormActions(Submit("submit", "Submit")),
2243
+ Div(
2244
+ HTML(
2245
+ """
2246
+ <div class="col-lg-4 col-lg-offset-4">
2247
+ <a href='"""
2248
+ + reverse("not_patient_indicators")
2249
+ + """' role="button" class="btn btn-default">
2250
+ Cancel and return to not-patient indicator summary page
2251
+ </a>
2252
+ </div>
2253
+ """
2254
+ )
2255
+ ),
2256
+ )
2257
+
2258
+ class Meta(object):
2259
+ model = NotPatientIndicatorsID
2260
+ fields = ["not_patient_id"]
2261
+ labels = {"not_patient_id": "pattern for ID matching"}
2262
+
2263
+
2264
+ class SkinSafeListForm(forms.ModelForm):
2265
+ """Form for adding/updating/removing system from openSkin safe list"""
2266
+
2267
+ class Meta(object):
2268
+ model = OpenSkinSafeList
2269
+ fields = ["manufacturer", "manufacturer_model_name", "software_version"]
2270
+
2271
+
2272
+ class BackgroundTaskMaximumRowsForm(forms.ModelForm):
2273
+ """Form for configuring the maximum number of rows in the BackgroundTask table"""
2274
+
2275
+ def __init__(self, *args, **kwargs):
2276
+ super(BackgroundTaskMaximumRowsForm, self).__init__(*args, **kwargs)
2277
+ self.helper = FormHelper(self)
2278
+ self.helper.form_class = "form-horizontal"
2279
+ self.helper.layout = Layout(
2280
+ Div("max_background_task_rows"),
2281
+ FormActions(Submit("submit", "Submit")),
2282
+ )
2283
+
2284
+ class Meta(object):
2285
+ model = BackgroundTaskMaximumRows
2286
+ fields = ["max_background_task_rows"]