diff --git a/rtbdi.toml b/rtbdi.toml
index 3a18595..010eeab 100644
--- a/rtbdi.toml
+++ b/rtbdi.toml
@@ -7,3 +7,5 @@ qr_ae_title = "OST"
ae_title = "TMS"
export_staging_directory = "~/BDIFolder"
plan_path = "~/SamplePlanFolder"
+# The AE Title for the ups scp that will respond to UPS C-FIND requests
+ups_scp_ae_title = "TMS"
diff --git a/tdwii_plus_examples/rtbdi_creator/form.ui b/tdwii_plus_examples/rtbdi_creator/form.ui
index b4c07f9..4447158 100644
--- a/tdwii_plus_examples/rtbdi_creator/form.ui
+++ b/tdwii_plus_examples/rtbdi_creator/form.ui
@@ -166,30 +166,6 @@
UPS Customization
- -
-
-
- Patient Photo
-
-
-
- -
-
-
- Scheduled DateTime
-
-
-
- -
-
-
- true
-
-
- Setup Photos
-
-
-
-
@@ -216,7 +192,7 @@
- -
+
-
@@ -229,6 +205,40 @@
+ -
+
+
+ TMS AE Title
+
+
+
+ -
+
+
+ Scheduled DateTime
+
+
+
+ -
+
+
+ Patient Photo
+
+
+
+ -
+
+
+ true
+
+
+ Setup Photos
+
+
+
+ -
+
+
diff --git a/tdwii_plus_examples/rtbdi_creator/mainbdiwidget.py b/tdwii_plus_examples/rtbdi_creator/mainbdiwidget.py
index 05c519c..979148d 100755
--- a/tdwii_plus_examples/rtbdi_creator/mainbdiwidget.py
+++ b/tdwii_plus_examples/rtbdi_creator/mainbdiwidget.py
@@ -33,6 +33,9 @@
write_ups,
)
+from tdwii_plus_examples.rtbdi_creator.ncreatescu import NCreateSCU
+from tdwii_plus_examples.rtbdi_creator.storescu import StoreSCU
+
class MainBDIWidget(QWidget):
"""Main UI for Creating an RT BDI based on an RT (Ion) Plan
@@ -65,9 +68,8 @@ def __init__(self, parent=None):
self.fraction_number = 1
self.retrieve_ae_title = ""
self.scheduled_datetime = datetime.now
- self.ae_title = "TMS"
+ self.ae_title = "TMS" # as an SCU... maybe should use a different AE Title?
config_file = "rtbdi.toml"
-
# TODO: command line argument specifying a different config file
try:
with open(config_file, "rb") as f:
@@ -78,11 +80,14 @@ def __init__(self, parent=None):
export_staging_directory = Path(default_dict["export_staging_directory"]).expanduser()
self.ui.lineedit_bdidir_selector.setText(str(export_staging_directory))
if "qr_ae_title" in default_dict:
- self.ui.line_edit_move_scp_ae_title.setText(toml_dict["DEFAULT"]["qr_ae_title"])
+ self.ui.line_edit_move_scp_ae_title.setText(default_dict["qr_ae_title"])
if "ae_title" in default_dict:
self.ae_title = default_dict["ae_title"]
if "plan_path" in default_dict:
self.plan_path = str(Path(default_dict["plan_path"]).expanduser())
+ if "ups_scp_ae_title" in default_dict:
+ self.ui.line_edit_tms_scp_ae_title.setText(default_dict["ups_scp_ae_title"])
+
else:
logging.warning("No [DEFAULT] section in toml config file")
@@ -109,25 +114,10 @@ def _store_plan_button_clicked(self):
iods = list()
iods.append(plan)
success = store_scu.store(iods=iods)
- self._store_outcome_message(success=success)
+ self._command_outcome_message(success=success, command_name="C-STORE")
return
- def _store_outcome_message(self, success: bool, text: str = None):
- # apparently a known defect, see:
- # https://stackoverflow.com/questions/76869543/why-cant-i-change-the-window-icon-on-a-qmessagebox-with-seticon-in-pyside6
- app.setAttribute(Qt.ApplicationAttribute.AA_DontUseNativeDialogs, True)
- if not success:
- dlg = QMessageBox(self)
- dlg.setIcon(QMessageBox.Warning)
- dlg.setText("C-STORE failed. Please check log for more information")
- else:
- dlg = QMessageBox(self)
- dlg.setIcon(QMessageBox.Information)
- dlg.setText("C-STORE succeeded")
- dlg.exec()
- app.setAttribute(Qt.ApplicationAttribute.AA_DontUseNativeDialogs, False)
-
@Slot()
def _bdidir_button_clicked(self):
dialog = QFileDialog(self, "BDI Export Dir")
@@ -165,7 +155,7 @@ def _bdi_export_button_clicked(self):
store_scu = StoreSCU(self.ae_title, self.ui.line_edit_move_scp_ae_title.text())
iods = [rtbdi]
success = store_scu.store(iods=iods)
- self._store_outcome_message(success=success)
+ self._command_outcome_message(success=success, command_name="C-STORE")
@Slot()
def _export_ups_button_clicked(self):
@@ -188,6 +178,38 @@ def _export_ups_button_clicked(self):
enable_setup_image_ref=self.ui.checkbox_setup_photos.isChecked(),
)
write_ups(ups, Path(self.ui.lineedit_bdidir_selector.text()))
+ tms_ae_title = self.ui.line_edit_tms_scp_ae_title.text()
+ if tms_ae_title is None or str(tms_ae_title.strip()) == 0:
+ logging.warning("No TMS AE Title specified, will not attempt an N-CREATE")
+ else:
+ ncreate_scu = NCreateSCU(self.ae_title, tms_ae_title.strip())
+ ups_list = list()
+ ups_list.append(ups)
+ success = ncreate_scu.create_ups(iods=ups_list)
+ self._command_outcome_message(success=success, command_name="N-CREATE")
+
+ def _command_outcome_message(self, success: bool, command_name: str, text: str = None):
+ # apparently a known defect, see:
+ # https://stackoverflow.com/questions/76869543/why-cant-i-change-the-window-icon-on-a-qmessagebox-with-seticon-in-pyside6
+ app.setAttribute(Qt.ApplicationAttribute.AA_DontUseNativeDialogs, True)
+ if not success:
+ dlg = QMessageBox(self)
+ dlg.setIcon(QMessageBox.Warning)
+ if text is None:
+ msg_text = " failed. Please check log for more information"
+ else:
+ msg_text = text
+ dlg.setText(command_name + msg_text)
+ else:
+ dlg = QMessageBox(self)
+ dlg.setIcon(QMessageBox.Information)
+ if text is None:
+ msg_text = " succeeded"
+ else:
+ msg_text = text
+ dlg.setText(command_name + msg_text)
+ dlg.exec()
+ app.setAttribute(Qt.ApplicationAttribute.AA_DontUseNativeDialogs, False)
def _validate_treatment_records(self, treatment_record_ds_list):
"""Confirms that the treatment records reference the plan
diff --git a/tdwii_plus_examples/rtbdi_creator/ncreatescu.py b/tdwii_plus_examples/rtbdi_creator/ncreatescu.py
new file mode 100644
index 0000000..f4737a0
--- /dev/null
+++ b/tdwii_plus_examples/rtbdi_creator/ncreatescu.py
@@ -0,0 +1,62 @@
+# StoreSCU.py
+import logging
+
+from pydicom import Dataset
+
+# from pydicom.errors import InvalidDicomError
+# from pydicom.uid import UID
+from pynetdicom import AE # , Association, UnifiedProcedurePresentationContexts
+from pynetdicom.presentation import build_context
+
+from tdwii_plus_examples import tdwii_config
+
+# from typing import Optional, Tuple
+
+
+# from pynetdicom.sop_class import UnifiedProcedureStepPush, UPSGlobalSubscriptionInstance
+# from pynetdicom import ALL_TRANSFER_SYNTAXES, AllStoragePresentationContexts, evt
+
+
+class NCreateSCU:
+ def __init__(
+ self,
+ sending_ae_title: str,
+ receiving_ae_title: str,
+ ):
+ self.calling_ae_title = sending_ae_title
+ self.receiving_ae_title = receiving_ae_title
+ tdwii_config.load_ae_config()
+
+ def create_ups(self, iods: list[Dataset], receiving_ae_title: str = None) -> bool:
+ ae = AE(ae_title=self.calling_ae_title)
+ dest_ae_title = self.receiving_ae_title
+ if receiving_ae_title is not None:
+ dest_ae_title = receiving_ae_title
+ contexts_in_iods = [build_context(x.SOPClassUID) for x in iods]
+ assoc = ae.associate(
+ tdwii_config.known_ae_ipaddr[dest_ae_title],
+ tdwii_config.known_ae_port[dest_ae_title],
+ contexts=contexts_in_iods,
+ ae_title=dest_ae_title,
+ )
+ success = False
+ if assoc.is_established:
+ msg_id = 0
+ success = True
+ for iod in iods:
+ msg_id += 1
+ response, _ = assoc.send_n_create(
+ iod, iod.SOPClassUID, iod.SOPInstanceUID, msg_id=msg_id, meta_uid=iod.SOPClassUID
+ )
+
+ if response is None or response.Status != 0x0000:
+ success = False
+ error_msg = "No response at all from {dest_ae_title} to N-CREATE-RQ"
+ if response is not None:
+ error_msg = f"Failed with status {response.Status} \
+ when trying to issue n-create for {iod.SOPInstanceUID} \
+ to {dest_ae_title}"
+ logging.error(error_msg)
+ break
+ assoc.release()
+ return success
diff --git a/tdwii_plus_examples/rtbdi_creator/ui_form.py b/tdwii_plus_examples/rtbdi_creator/ui_form.py
index 291d83e..13b49e4 100644
--- a/tdwii_plus_examples/rtbdi_creator/ui_form.py
+++ b/tdwii_plus_examples/rtbdi_creator/ui_form.py
@@ -1,223 +1,282 @@
-# -*- coding: utf-8 -*-
-
-################################################################################
-## Form generated from reading UI file 'form.ui'
-##
-## Created by: Qt User Interface Compiler version 6.7.2
-##
-## WARNING! All changes made in this file will be lost when recompiling UI file!
-################################################################################
-
-from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
- QMetaObject, QObject, QPoint, QRect,
- QSize, QTime, QUrl, Qt)
-from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
- QFont, QFontDatabase, QGradient, QIcon,
- QImage, QKeySequence, QLinearGradient, QPainter,
- QPalette, QPixmap, QRadialGradient, QTransform)
-from PySide6.QtWidgets import (QApplication, QCheckBox, QDateTimeEdit, QDoubleSpinBox,
- QGridLayout, QGroupBox, QLabel, QLineEdit,
- QListView, QPushButton, QSizePolicy, QVBoxLayout,
- QWidget)
-
-class Ui_MainBDIWidget(object):
- def setupUi(self, MainBDIWidget):
- if not MainBDIWidget.objectName():
- MainBDIWidget.setObjectName(u"MainBDIWidget")
- MainBDIWidget.resize(600, 600)
- self.verticalLayout_2 = QVBoxLayout(MainBDIWidget)
- self.verticalLayout_2.setObjectName(u"verticalLayout_2")
- self.group_box_main = QGroupBox(MainBDIWidget)
- self.group_box_main.setObjectName(u"group_box_main")
- self.gridLayout_5 = QGridLayout(self.group_box_main)
- self.gridLayout_5.setObjectName(u"gridLayout_5")
- self.label_move_ae_title = QLabel(self.group_box_main)
- self.label_move_ae_title.setObjectName(u"label_move_ae_title")
-
- self.gridLayout_5.addWidget(self.label_move_ae_title, 0, 0, 1, 1)
-
- self.line_edit_move_scp_ae_title = QLineEdit(self.group_box_main)
- self.line_edit_move_scp_ae_title.setObjectName(u"line_edit_move_scp_ae_title")
-
- self.gridLayout_5.addWidget(self.line_edit_move_scp_ae_title, 0, 1, 1, 1)
-
-
- self.verticalLayout_2.addWidget(self.group_box_main)
-
- self.group_box_plan_selection = QGroupBox(MainBDIWidget)
- self.group_box_plan_selection.setObjectName(u"group_box_plan_selection")
- self.gridLayout_4 = QGridLayout(self.group_box_plan_selection)
- self.gridLayout_4.setObjectName(u"gridLayout_4")
- self.lineedit_plan_selector = QLineEdit(self.group_box_plan_selection)
- self.lineedit_plan_selector.setObjectName(u"lineedit_plan_selector")
-
- self.gridLayout_4.addWidget(self.lineedit_plan_selector, 0, 1, 1, 1)
-
- self.label_plan_selector = QLabel(self.group_box_plan_selection)
- self.label_plan_selector.setObjectName(u"label_plan_selector")
-
- self.gridLayout_4.addWidget(self.label_plan_selector, 0, 0, 1, 1)
-
- self.push_button_plan_finder = QPushButton(self.group_box_plan_selection)
- self.push_button_plan_finder.setObjectName(u"push_button_plan_finder")
-
- self.gridLayout_4.addWidget(self.push_button_plan_finder, 0, 2, 1, 1)
-
- self.push_button_send_plan = QPushButton(self.group_box_plan_selection)
- self.push_button_send_plan.setObjectName(u"push_button_send_plan")
-
- self.gridLayout_4.addWidget(self.push_button_send_plan, 0, 3, 1, 1)
-
-
- self.verticalLayout_2.addWidget(self.group_box_plan_selection)
-
- self.group_box_bdi_variables = QGroupBox(MainBDIWidget)
- self.group_box_bdi_variables.setObjectName(u"group_box_bdi_variables")
- sizePolicy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.group_box_bdi_variables.sizePolicy().hasHeightForWidth())
- self.group_box_bdi_variables.setSizePolicy(sizePolicy)
- self.gridLayout_3 = QGridLayout(self.group_box_bdi_variables)
- self.gridLayout_3.setObjectName(u"gridLayout_3")
- self.list_view_treatment_records = QListView(self.group_box_bdi_variables)
- self.list_view_treatment_records.setObjectName(u"list_view_treatment_records")
-
- self.gridLayout_3.addWidget(self.list_view_treatment_records, 1, 0, 1, 1)
-
- self.label_fraction_number = QLabel(self.group_box_bdi_variables)
- self.label_fraction_number.setObjectName(u"label_fraction_number")
-
- self.gridLayout_3.addWidget(self.label_fraction_number, 0, 0, 1, 1)
-
- self.push_button_load_treatment_records = QPushButton(self.group_box_bdi_variables)
- self.push_button_load_treatment_records.setObjectName(u"push_button_load_treatment_records")
-
- self.gridLayout_3.addWidget(self.push_button_load_treatment_records, 1, 1, 1, 1)
-
- self.double_spin_box_fraction_number = QDoubleSpinBox(self.group_box_bdi_variables)
- self.double_spin_box_fraction_number.setObjectName(u"double_spin_box_fraction_number")
- self.double_spin_box_fraction_number.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
- self.double_spin_box_fraction_number.setDecimals(0)
- self.double_spin_box_fraction_number.setValue(1.000000000000000)
-
- self.gridLayout_3.addWidget(self.double_spin_box_fraction_number, 0, 1, 1, 1)
-
-
- self.verticalLayout_2.addWidget(self.group_box_bdi_variables)
-
- self.group_box_bdi_output = QGroupBox(MainBDIWidget)
- self.group_box_bdi_output.setObjectName(u"group_box_bdi_output")
- self.gridLayout_2 = QGridLayout(self.group_box_bdi_output)
- self.gridLayout_2.setObjectName(u"gridLayout_2")
- self.line_edit_bdi_filename = QLineEdit(self.group_box_bdi_output)
- self.line_edit_bdi_filename.setObjectName(u"line_edit_bdi_filename")
-
- self.gridLayout_2.addWidget(self.line_edit_bdi_filename, 1, 2, 1, 1)
-
- self.push_button_bdi_dir_finder = QPushButton(self.group_box_bdi_output)
- self.push_button_bdi_dir_finder.setObjectName(u"push_button_bdi_dir_finder")
-
- self.gridLayout_2.addWidget(self.push_button_bdi_dir_finder, 0, 3, 1, 1)
-
- self.lineedit_bdidir_selector = QLineEdit(self.group_box_bdi_output)
- self.lineedit_bdidir_selector.setObjectName(u"lineedit_bdidir_selector")
-
- self.gridLayout_2.addWidget(self.lineedit_bdidir_selector, 0, 1, 1, 2)
-
- self.label_bdi_output_dir = QLabel(self.group_box_bdi_output)
- self.label_bdi_output_dir.setObjectName(u"label_bdi_output_dir")
-
- self.gridLayout_2.addWidget(self.label_bdi_output_dir, 0, 0, 1, 1)
-
- self.checkbox_custom_bdi_filename = QCheckBox(self.group_box_bdi_output)
- self.checkbox_custom_bdi_filename.setObjectName(u"checkbox_custom_bdi_filename")
-
- self.gridLayout_2.addWidget(self.checkbox_custom_bdi_filename, 1, 0, 1, 2)
-
- self.push_button_export_bdi = QPushButton(self.group_box_bdi_output)
- self.push_button_export_bdi.setObjectName(u"push_button_export_bdi")
-
- self.gridLayout_2.addWidget(self.push_button_export_bdi, 2, 3, 1, 1)
-
-
- self.verticalLayout_2.addWidget(self.group_box_bdi_output)
-
- self.group_box_ups = QGroupBox(MainBDIWidget)
- self.group_box_ups.setObjectName(u"group_box_ups")
- self.gridLayout = QGridLayout(self.group_box_ups)
- self.gridLayout.setObjectName(u"gridLayout")
- self.checkbox_patient_photo = QCheckBox(self.group_box_ups)
- self.checkbox_patient_photo.setObjectName(u"checkbox_patient_photo")
-
- self.gridLayout.addWidget(self.checkbox_patient_photo, 1, 2, 1, 1)
-
- self.label_start_datetime = QLabel(self.group_box_ups)
- self.label_start_datetime.setObjectName(u"label_start_datetime")
-
- self.gridLayout.addWidget(self.label_start_datetime, 1, 0, 1, 1)
-
- self.checkbox_setup_photos = QCheckBox(self.group_box_ups)
- self.checkbox_setup_photos.setObjectName(u"checkbox_setup_photos")
- self.checkbox_setup_photos.setEnabled(True)
-
- self.gridLayout.addWidget(self.checkbox_setup_photos, 2, 2, 1, 1)
-
- self.datetime_edit_scheduled_datetime = QDateTimeEdit(self.group_box_ups)
- self.datetime_edit_scheduled_datetime.setObjectName(u"datetime_edit_scheduled_datetime")
- sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)
- sizePolicy1.setHorizontalStretch(0)
- sizePolicy1.setVerticalStretch(0)
- sizePolicy1.setHeightForWidth(self.datetime_edit_scheduled_datetime.sizePolicy().hasHeightForWidth())
- self.datetime_edit_scheduled_datetime.setSizePolicy(sizePolicy1)
- self.datetime_edit_scheduled_datetime.setDateTime(QDateTime(QDate(2023, 9, 1), QTime(0, 0, 0)))
- self.datetime_edit_scheduled_datetime.setCalendarPopup(True)
-
- self.gridLayout.addWidget(self.datetime_edit_scheduled_datetime, 1, 1, 1, 1)
-
- self.push_button_export_ups = QPushButton(self.group_box_ups)
- self.push_button_export_ups.setObjectName(u"push_button_export_ups")
- sizePolicy1.setHeightForWidth(self.push_button_export_ups.sizePolicy().hasHeightForWidth())
- self.push_button_export_ups.setSizePolicy(sizePolicy1)
-
- self.gridLayout.addWidget(self.push_button_export_ups, 3, 1, 1, 1)
-
-
- self.verticalLayout_2.addWidget(self.group_box_ups)
-
-
- self.retranslateUi(MainBDIWidget)
-
- QMetaObject.connectSlotsByName(MainBDIWidget)
- # setupUi
-
- def retranslateUi(self, MainBDIWidget):
- MainBDIWidget.setWindowTitle(QCoreApplication.translate("MainBDIWidget", u"RT Beams Delivery Instruction and UPS Creator", None))
- self.group_box_main.setTitle("")
- self.label_move_ae_title.setText(QCoreApplication.translate("MainBDIWidget", u"Move/Retrieve AE Title", None))
- self.group_box_plan_selection.setTitle(QCoreApplication.translate("MainBDIWidget", u"Plan Selection", None))
- self.label_plan_selector.setText(QCoreApplication.translate("MainBDIWidget", u"RT (Ion) Plan", None))
- self.push_button_plan_finder.setText(QCoreApplication.translate("MainBDIWidget", u"Find Plan", None))
- self.push_button_send_plan.setText(QCoreApplication.translate("MainBDIWidget", u"Store Plan", None))
- self.group_box_bdi_variables.setTitle(QCoreApplication.translate("MainBDIWidget", u"BDI Customization", None))
- self.label_fraction_number.setText(QCoreApplication.translate("MainBDIWidget", u"Fraction #", None))
-#if QT_CONFIG(tooltip)
- self.push_button_load_treatment_records.setToolTip(QCoreApplication.translate("MainBDIWidget", u"
Simulate a partially treated session.
The treatment records selected must reference the RT (Ion) Plan selected, and the Current Fraction Number in the RT (Ion) Beams Session records must match the Fraction # specified
", None))
-#endif // QT_CONFIG(tooltip)
- self.push_button_load_treatment_records.setText(QCoreApplication.translate("MainBDIWidget", u"Treatment Records", None))
- self.group_box_bdi_output.setTitle(QCoreApplication.translate("MainBDIWidget", u"BDI Output", None))
- self.push_button_bdi_dir_finder.setText(QCoreApplication.translate("MainBDIWidget", u"Choose BDI Dir", None))
- self.label_bdi_output_dir.setText(QCoreApplication.translate("MainBDIWidget", u"BDI Output Dir", None))
-#if QT_CONFIG(tooltip)
- self.checkbox_custom_bdi_filename.setToolTip(QCoreApplication.translate("MainBDIWidget", u"When checked, the value entered will be used for the RT Beams Delivery Instruction file name.
If left unchecked, the file name for the RT Beams Delivery Instruction will be of the format RB_<SOP Instance UID>.dcm
", None))
-#endif // QT_CONFIG(tooltip)
- self.checkbox_custom_bdi_filename.setText(QCoreApplication.translate("MainBDIWidget", u"Custom BDI filename", None))
- self.push_button_export_bdi.setText(QCoreApplication.translate("MainBDIWidget", u"Export BDI", None))
- self.group_box_ups.setTitle(QCoreApplication.translate("MainBDIWidget", u"UPS Customization", None))
- self.checkbox_patient_photo.setText(QCoreApplication.translate("MainBDIWidget", u"Patient Photo", None))
- self.label_start_datetime.setText(QCoreApplication.translate("MainBDIWidget", u"Scheduled DateTime", None))
- self.checkbox_setup_photos.setText(QCoreApplication.translate("MainBDIWidget", u"Setup Photos", None))
- self.datetime_edit_scheduled_datetime.setDisplayFormat(QCoreApplication.translate("MainBDIWidget", u"dd/MM/yyyy h:mm AP", None))
- self.push_button_export_ups.setText(QCoreApplication.translate("MainBDIWidget", u"Export UPS", None))
- # retranslateUi
-
+# -*- coding: utf-8 -*-
+
+################################################################################
+## Form generated from reading UI file 'form.ui'
+##
+## Created by: Qt User Interface Compiler version 6.7.1
+##
+## WARNING! All changes made in this file will be lost when recompiling UI file!
+################################################################################
+
+from PySide6.QtCore import (
+ QCoreApplication,
+ QDate,
+ QDateTime,
+ QLocale,
+ QMetaObject,
+ QObject,
+ QPoint,
+ QRect,
+ QSize,
+ Qt,
+ QTime,
+ QUrl,
+)
+from PySide6.QtGui import (
+ QBrush,
+ QColor,
+ QConicalGradient,
+ QCursor,
+ QFont,
+ QFontDatabase,
+ QGradient,
+ QIcon,
+ QImage,
+ QKeySequence,
+ QLinearGradient,
+ QPainter,
+ QPalette,
+ QPixmap,
+ QRadialGradient,
+ QTransform,
+)
+from PySide6.QtWidgets import (
+ QApplication,
+ QCheckBox,
+ QDateTimeEdit,
+ QDoubleSpinBox,
+ QGridLayout,
+ QGroupBox,
+ QLabel,
+ QLineEdit,
+ QListView,
+ QPushButton,
+ QSizePolicy,
+ QVBoxLayout,
+ QWidget,
+)
+
+
+class Ui_MainBDIWidget(object):
+ def setupUi(self, MainBDIWidget):
+ if not MainBDIWidget.objectName():
+ MainBDIWidget.setObjectName("MainBDIWidget")
+ MainBDIWidget.resize(600, 600)
+ self.verticalLayout_2 = QVBoxLayout(MainBDIWidget)
+ self.verticalLayout_2.setObjectName("verticalLayout_2")
+ self.group_box_main = QGroupBox(MainBDIWidget)
+ self.group_box_main.setObjectName("group_box_main")
+ self.gridLayout_5 = QGridLayout(self.group_box_main)
+ self.gridLayout_5.setObjectName("gridLayout_5")
+ self.label_move_ae_title = QLabel(self.group_box_main)
+ self.label_move_ae_title.setObjectName("label_move_ae_title")
+
+ self.gridLayout_5.addWidget(self.label_move_ae_title, 0, 0, 1, 1)
+
+ self.line_edit_move_scp_ae_title = QLineEdit(self.group_box_main)
+ self.line_edit_move_scp_ae_title.setObjectName("line_edit_move_scp_ae_title")
+
+ self.gridLayout_5.addWidget(self.line_edit_move_scp_ae_title, 0, 1, 1, 1)
+
+ self.verticalLayout_2.addWidget(self.group_box_main)
+
+ self.group_box_plan_selection = QGroupBox(MainBDIWidget)
+ self.group_box_plan_selection.setObjectName("group_box_plan_selection")
+ self.gridLayout_4 = QGridLayout(self.group_box_plan_selection)
+ self.gridLayout_4.setObjectName("gridLayout_4")
+ self.lineedit_plan_selector = QLineEdit(self.group_box_plan_selection)
+ self.lineedit_plan_selector.setObjectName("lineedit_plan_selector")
+
+ self.gridLayout_4.addWidget(self.lineedit_plan_selector, 0, 1, 1, 1)
+
+ self.label_plan_selector = QLabel(self.group_box_plan_selection)
+ self.label_plan_selector.setObjectName("label_plan_selector")
+
+ self.gridLayout_4.addWidget(self.label_plan_selector, 0, 0, 1, 1)
+
+ self.push_button_plan_finder = QPushButton(self.group_box_plan_selection)
+ self.push_button_plan_finder.setObjectName("push_button_plan_finder")
+
+ self.gridLayout_4.addWidget(self.push_button_plan_finder, 0, 2, 1, 1)
+
+ self.push_button_send_plan = QPushButton(self.group_box_plan_selection)
+ self.push_button_send_plan.setObjectName("push_button_send_plan")
+
+ self.gridLayout_4.addWidget(self.push_button_send_plan, 0, 3, 1, 1)
+
+ self.verticalLayout_2.addWidget(self.group_box_plan_selection)
+
+ self.group_box_bdi_variables = QGroupBox(MainBDIWidget)
+ self.group_box_bdi_variables.setObjectName("group_box_bdi_variables")
+ sizePolicy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.group_box_bdi_variables.sizePolicy().hasHeightForWidth())
+ self.group_box_bdi_variables.setSizePolicy(sizePolicy)
+ self.gridLayout_3 = QGridLayout(self.group_box_bdi_variables)
+ self.gridLayout_3.setObjectName("gridLayout_3")
+ self.list_view_treatment_records = QListView(self.group_box_bdi_variables)
+ self.list_view_treatment_records.setObjectName("list_view_treatment_records")
+
+ self.gridLayout_3.addWidget(self.list_view_treatment_records, 1, 0, 1, 1)
+
+ self.label_fraction_number = QLabel(self.group_box_bdi_variables)
+ self.label_fraction_number.setObjectName("label_fraction_number")
+
+ self.gridLayout_3.addWidget(self.label_fraction_number, 0, 0, 1, 1)
+
+ self.push_button_load_treatment_records = QPushButton(self.group_box_bdi_variables)
+ self.push_button_load_treatment_records.setObjectName("push_button_load_treatment_records")
+
+ self.gridLayout_3.addWidget(self.push_button_load_treatment_records, 1, 1, 1, 1)
+
+ self.double_spin_box_fraction_number = QDoubleSpinBox(self.group_box_bdi_variables)
+ self.double_spin_box_fraction_number.setObjectName("double_spin_box_fraction_number")
+ self.double_spin_box_fraction_number.setAlignment(Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter)
+ self.double_spin_box_fraction_number.setDecimals(0)
+ self.double_spin_box_fraction_number.setValue(1.000000000000000)
+
+ self.gridLayout_3.addWidget(self.double_spin_box_fraction_number, 0, 1, 1, 1)
+
+ self.verticalLayout_2.addWidget(self.group_box_bdi_variables)
+
+ self.group_box_bdi_output = QGroupBox(MainBDIWidget)
+ self.group_box_bdi_output.setObjectName("group_box_bdi_output")
+ self.gridLayout_2 = QGridLayout(self.group_box_bdi_output)
+ self.gridLayout_2.setObjectName("gridLayout_2")
+ self.line_edit_bdi_filename = QLineEdit(self.group_box_bdi_output)
+ self.line_edit_bdi_filename.setObjectName("line_edit_bdi_filename")
+
+ self.gridLayout_2.addWidget(self.line_edit_bdi_filename, 1, 2, 1, 1)
+
+ self.push_button_bdi_dir_finder = QPushButton(self.group_box_bdi_output)
+ self.push_button_bdi_dir_finder.setObjectName("push_button_bdi_dir_finder")
+
+ self.gridLayout_2.addWidget(self.push_button_bdi_dir_finder, 0, 3, 1, 1)
+
+ self.lineedit_bdidir_selector = QLineEdit(self.group_box_bdi_output)
+ self.lineedit_bdidir_selector.setObjectName("lineedit_bdidir_selector")
+
+ self.gridLayout_2.addWidget(self.lineedit_bdidir_selector, 0, 1, 1, 2)
+
+ self.label_bdi_output_dir = QLabel(self.group_box_bdi_output)
+ self.label_bdi_output_dir.setObjectName("label_bdi_output_dir")
+
+ self.gridLayout_2.addWidget(self.label_bdi_output_dir, 0, 0, 1, 1)
+
+ self.checkbox_custom_bdi_filename = QCheckBox(self.group_box_bdi_output)
+ self.checkbox_custom_bdi_filename.setObjectName("checkbox_custom_bdi_filename")
+
+ self.gridLayout_2.addWidget(self.checkbox_custom_bdi_filename, 1, 0, 1, 2)
+
+ self.push_button_export_bdi = QPushButton(self.group_box_bdi_output)
+ self.push_button_export_bdi.setObjectName("push_button_export_bdi")
+
+ self.gridLayout_2.addWidget(self.push_button_export_bdi, 2, 3, 1, 1)
+
+ self.verticalLayout_2.addWidget(self.group_box_bdi_output)
+
+ self.group_box_ups = QGroupBox(MainBDIWidget)
+ self.group_box_ups.setObjectName("group_box_ups")
+ self.gridLayout = QGridLayout(self.group_box_ups)
+ self.gridLayout.setObjectName("gridLayout")
+ self.datetime_edit_scheduled_datetime = QDateTimeEdit(self.group_box_ups)
+ self.datetime_edit_scheduled_datetime.setObjectName("datetime_edit_scheduled_datetime")
+ sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)
+ sizePolicy1.setHorizontalStretch(0)
+ sizePolicy1.setVerticalStretch(0)
+ sizePolicy1.setHeightForWidth(self.datetime_edit_scheduled_datetime.sizePolicy().hasHeightForWidth())
+ self.datetime_edit_scheduled_datetime.setSizePolicy(sizePolicy1)
+ self.datetime_edit_scheduled_datetime.setDateTime(QDateTime(QDate(2023, 9, 1), QTime(0, 0, 0)))
+ self.datetime_edit_scheduled_datetime.setCalendarPopup(True)
+
+ self.gridLayout.addWidget(self.datetime_edit_scheduled_datetime, 1, 1, 1, 1)
+
+ self.push_button_export_ups = QPushButton(self.group_box_ups)
+ self.push_button_export_ups.setObjectName("push_button_export_ups")
+ sizePolicy1.setHeightForWidth(self.push_button_export_ups.sizePolicy().hasHeightForWidth())
+ self.push_button_export_ups.setSizePolicy(sizePolicy1)
+
+ self.gridLayout.addWidget(self.push_button_export_ups, 4, 2, 1, 1)
+
+ self.label_tms_scp_ae_title = QLabel(self.group_box_ups)
+ self.label_tms_scp_ae_title.setObjectName("label_tms_scp_ae_title")
+
+ self.gridLayout.addWidget(self.label_tms_scp_ae_title, 4, 0, 1, 1)
+
+ self.label_start_datetime = QLabel(self.group_box_ups)
+ self.label_start_datetime.setObjectName("label_start_datetime")
+
+ self.gridLayout.addWidget(self.label_start_datetime, 1, 0, 1, 1)
+
+ self.checkbox_patient_photo = QCheckBox(self.group_box_ups)
+ self.checkbox_patient_photo.setObjectName("checkbox_patient_photo")
+
+ self.gridLayout.addWidget(self.checkbox_patient_photo, 1, 2, 1, 1)
+
+ self.checkbox_setup_photos = QCheckBox(self.group_box_ups)
+ self.checkbox_setup_photos.setObjectName("checkbox_setup_photos")
+ self.checkbox_setup_photos.setEnabled(True)
+
+ self.gridLayout.addWidget(self.checkbox_setup_photos, 2, 2, 1, 1)
+
+ self.line_edit_tms_scp_ae_title = QLineEdit(self.group_box_ups)
+ self.line_edit_tms_scp_ae_title.setObjectName("line_edit_tms_scp_ae_title")
+
+ self.gridLayout.addWidget(self.line_edit_tms_scp_ae_title, 4, 1, 1, 1)
+
+ self.verticalLayout_2.addWidget(self.group_box_ups)
+
+ self.retranslateUi(MainBDIWidget)
+
+ QMetaObject.connectSlotsByName(MainBDIWidget)
+
+ # setupUi
+
+ def retranslateUi(self, MainBDIWidget):
+ MainBDIWidget.setWindowTitle(
+ QCoreApplication.translate("MainBDIWidget", "RT Beams Delivery Instruction and UPS Creator", None)
+ )
+ self.group_box_main.setTitle("")
+ self.label_move_ae_title.setText(QCoreApplication.translate("MainBDIWidget", "Move/Retrieve AE Title", None))
+ self.group_box_plan_selection.setTitle(QCoreApplication.translate("MainBDIWidget", "Plan Selection", None))
+ self.label_plan_selector.setText(QCoreApplication.translate("MainBDIWidget", "RT (Ion) Plan", None))
+ self.push_button_plan_finder.setText(QCoreApplication.translate("MainBDIWidget", "Find Plan", None))
+ self.push_button_send_plan.setText(QCoreApplication.translate("MainBDIWidget", "Store Plan", None))
+ self.group_box_bdi_variables.setTitle(QCoreApplication.translate("MainBDIWidget", "BDI Customization", None))
+ self.label_fraction_number.setText(QCoreApplication.translate("MainBDIWidget", "Fraction #", None))
+ # if QT_CONFIG(tooltip)
+ self.push_button_load_treatment_records.setToolTip(
+ QCoreApplication.translate(
+ "MainBDIWidget",
+ "Simulate a partially treated session.
The treatment records selected must reference the RT (Ion) Plan selected, and the Current Fraction Number in the RT (Ion) Beams Session records must match the Fraction # specified
",
+ None,
+ )
+ )
+ # endif // QT_CONFIG(tooltip)
+ self.push_button_load_treatment_records.setText(QCoreApplication.translate("MainBDIWidget", "Treatment Records", None))
+ self.group_box_bdi_output.setTitle(QCoreApplication.translate("MainBDIWidget", "BDI Output", None))
+ self.push_button_bdi_dir_finder.setText(QCoreApplication.translate("MainBDIWidget", "Choose BDI Dir", None))
+ self.label_bdi_output_dir.setText(QCoreApplication.translate("MainBDIWidget", "BDI Output Dir", None))
+ # if QT_CONFIG(tooltip)
+ self.checkbox_custom_bdi_filename.setToolTip(
+ QCoreApplication.translate(
+ "MainBDIWidget",
+ "When checked, the value entered will be used for the RT Beams Delivery Instruction file name.
If left unchecked, the file name for the RT Beams Delivery Instruction will be of the format RB_<SOP Instance UID>.dcm
",
+ None,
+ )
+ )
+ # endif // QT_CONFIG(tooltip)
+ self.checkbox_custom_bdi_filename.setText(QCoreApplication.translate("MainBDIWidget", "Custom BDI filename", None))
+ self.push_button_export_bdi.setText(QCoreApplication.translate("MainBDIWidget", "Export BDI", None))
+ self.group_box_ups.setTitle(QCoreApplication.translate("MainBDIWidget", "UPS Customization", None))
+ self.datetime_edit_scheduled_datetime.setDisplayFormat(
+ QCoreApplication.translate("MainBDIWidget", "dd/MM/yyyy h:mm AP", None)
+ )
+ self.push_button_export_ups.setText(QCoreApplication.translate("MainBDIWidget", "Export UPS", None))
+ self.label_tms_scp_ae_title.setText(QCoreApplication.translate("MainBDIWidget", "TMS AE Title", None))
+ self.label_start_datetime.setText(QCoreApplication.translate("MainBDIWidget", "Scheduled DateTime", None))
+ self.checkbox_patient_photo.setText(QCoreApplication.translate("MainBDIWidget", "Patient Photo", None))
+ self.checkbox_setup_photos.setText(QCoreApplication.translate("MainBDIWidget", "Setup Photos", None))
+
+ # retranslateUi