Beispiel #1
0
    def __init__(self):
        super(Window, self).__init__()
        self.installEventFilter(self)

        layout = QHBoxLayout()

        layout.setSpacing(0)
        layout.setContentsMargins(10, 10, 10, 10)

        layout.addWidget(self.createMainSection())
        layout.setStretch(0, 580)
        self.patchbay = self.createPatchbay()
        layout.addWidget(self.patchbay)
        layout.setStretch(1, 280)

        layout.setSpacing(8)

        self.setStyleSheet(mainWindowStyleSheet())

        centralWidget = QWidget(self)
        self.setCentralWidget(centralWidget)
        centralWidget.setLayout(layout)

        self.setWindowTitle("Sharm v2")
        path = join("gui", "images", "icon.svg")
        self.setWindowIcon(QtGui.QIcon(path))
        # self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.FramelessWindowHint)
        self.setFocus()
Beispiel #2
0
def test_pixmap_vertical(pixmap_differ: PixmapDiffer):
    actual: QPainter
    expected: QPainter
    with pixmap_differ.create_painters(
            300, 240, 'scaled_label_pixmap_vertical') as (actual, expected):
        ex_widget = QWidget()
        ex_widget.resize(300, 240)
        expected.drawPixmap(0, 0, ex_widget.grab())
        icon = GridDisplay.create_icon(GridDisplay.player2_colour)

        expected.drawPixmap(
            0, 0,
            icon.scaled(150, 150, Qt.KeepAspectRatio, Qt.SmoothTransformation))
        expected.drawPixmap(
            150, 70,
            icon.scaled(100, 100, Qt.KeepAspectRatio, Qt.SmoothTransformation))
        expected.drawPixmap(
            250, 190,
            icon.scaled(50, 50, Qt.KeepAspectRatio, Qt.SmoothTransformation))

        widget = QWidget()
        layout = QHBoxLayout(widget)
        label1 = ScaledLabel()
        label2 = ScaledLabel()
        label3 = ScaledLabel()
        label1.setPixmap(icon)
        label2.setPixmap(icon)
        label3.setPixmap(icon)
        size_policy = QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
        label1.setSizePolicy(size_policy)
        label2.setSizePolicy(size_policy)
        label3.setSizePolicy(size_policy)
        label1.setScaledContents(True)
        label2.setScaledContents(True)
        label3.setScaledContents(True)
        label1.setAlignment(Qt.AlignTop)
        label2.setAlignment(Qt.AlignCenter)
        label3.setAlignment(Qt.AlignBottom)
        layout.addWidget(label1)
        layout.addWidget(label2)
        layout.addWidget(label3)
        layout.setStretch(0, 3)
        layout.setStretch(1, 2)
        layout.setStretch(2, 1)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)

        widget.resize(300, 240)

        actual.drawPixmap(0, 0, widget.grab())
Beispiel #3
0
    def createTopControls(self):
        widget = QWidget()
        layout = QHBoxLayout()

        layout.addWidget(self.createSequencerControls())
        layout.addStretch(1)
        layout.addWidget(self.createVcoSection())

        layout.setContentsMargins(0, 0, 0, 0)
        layout.setStretch(0, 8)

        layout.setStretch(2, 8)

        widget.setContentsMargins(0, 0, 0, 0)

        widget.setLayout(layout)
        return widget
Beispiel #4
0
class UIOpenPatientWindow(object):
    patient_info_initialized = QtCore.Signal(object)

    def setup_ui(self, open_patient_window_instance):
        if platform.system() == 'Darwin':
            self.stylesheet_path = "res/stylesheet.qss"
        else:
            self.stylesheet_path = "res/stylesheet-win-linux.qss"

        window_icon = QIcon()
        window_icon.addPixmap(QPixmap(resource_path("res/images/icon.ico")),
                              QIcon.Normal, QIcon.Off)
        open_patient_window_instance.setObjectName("OpenPatientWindowInstance")
        open_patient_window_instance.setWindowIcon(window_icon)
        open_patient_window_instance.resize(840, 530)

        # Create a vertical box for containing the other elements and layouts
        self.open_patient_window_instance_vertical_box = QVBoxLayout()
        self.open_patient_window_instance_vertical_box.setObjectName(
            "OpenPatientWindowInstanceVerticalBox")

        # Create a label to prompt the user to enter the path to the directory that contains the DICOM files
        self.open_patient_directory_prompt = QLabel()
        self.open_patient_directory_prompt.setObjectName(
            "OpenPatientDirectoryPrompt")
        self.open_patient_directory_prompt.setAlignment(Qt.AlignLeft)
        self.open_patient_window_instance_vertical_box.addWidget(
            self.open_patient_directory_prompt)

        # Create a horizontal box to hold the input box for the directory and the choose button
        self.open_patient_directory_input_horizontal_box = QHBoxLayout()
        self.open_patient_directory_input_horizontal_box.setObjectName(
            "OpenPatientDirectoryInputHorizontalBox")
        # Create a textbox to contain the path to the directory that contains the DICOM files
        self.open_patient_directory_input_box = UIOpenPatientWindowDragAndDropEvent(
            self)

        self.open_patient_directory_input_box.setObjectName(
            "OpenPatientDirectoryInputBox")
        self.open_patient_directory_input_box.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.open_patient_directory_input_box.returnPressed.connect(
            self.scan_directory_for_patient)
        self.open_patient_directory_input_horizontal_box.addWidget(
            self.open_patient_directory_input_box)

        # Create a choose button to open the file dialog
        self.open_patient_directory_choose_button = QPushButton()
        self.open_patient_directory_choose_button.setObjectName(
            "OpenPatientDirectoryChooseButton")
        self.open_patient_directory_choose_button.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.open_patient_directory_choose_button.resize(
            self.open_patient_directory_choose_button.sizeHint().width(),
            self.open_patient_directory_input_box.height())
        self.open_patient_directory_choose_button.setCursor(
            QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.open_patient_directory_input_horizontal_box.addWidget(
            self.open_patient_directory_choose_button)
        self.open_patient_directory_choose_button.clicked.connect(
            self.choose_button_clicked)
        # Create a widget to hold the input fields
        self.open_patient_directory_input_widget = QWidget()
        self.open_patient_directory_input_horizontal_box.setStretch(0, 4)
        self.open_patient_directory_input_widget.setLayout(
            self.open_patient_directory_input_horizontal_box)
        self.open_patient_window_instance_vertical_box.addWidget(
            self.open_patient_directory_input_widget)

        # Create a horizontal box to hold the stop button and direction to the user on where to select the patient
        self.open_patient_appear_prompt_and_stop_horizontal_box = QHBoxLayout()
        self.open_patient_appear_prompt_and_stop_horizontal_box.setObjectName(
            "OpenPatientAppearPromptAndStopHorizontalBox")
        # Create a label to show direction on where the files will appear
        self.open_patient_directory_appear_prompt = QLabel()
        self.open_patient_directory_appear_prompt.setObjectName(
            "OpenPatientDirectoryAppearPrompt")
        self.open_patient_directory_appear_prompt.setAlignment(Qt.AlignLeft)
        self.open_patient_appear_prompt_and_stop_horizontal_box.addWidget(
            self.open_patient_directory_appear_prompt)
        self.open_patient_appear_prompt_and_stop_horizontal_box.addStretch(1)
        # Create a button to stop searching
        self.open_patient_window_stop_button = QPushButton()
        self.open_patient_window_stop_button.setObjectName(
            "OpenPatientWindowStopButton")
        self.open_patient_window_stop_button.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.open_patient_window_stop_button.resize(
            self.open_patient_window_stop_button.sizeHint().width(),
            self.open_patient_window_stop_button.sizeHint().height())
        self.open_patient_window_stop_button.setCursor(
            QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.open_patient_window_stop_button.clicked.connect(
            self.stop_button_clicked)
        self.open_patient_window_stop_button.setProperty(
            "QPushButtonClass", "fail-button")
        self.open_patient_window_stop_button.setVisible(
            False)  # Button doesn't show until a search commences
        self.open_patient_appear_prompt_and_stop_horizontal_box.addWidget(
            self.open_patient_window_stop_button)
        # Create a widget to hold the layout
        self.open_patient_appear_prompt_and_stop_widget = QWidget()
        self.open_patient_appear_prompt_and_stop_widget.setLayout(
            self.open_patient_appear_prompt_and_stop_horizontal_box)
        self.open_patient_window_instance_vertical_box.addWidget(
            self.open_patient_appear_prompt_and_stop_widget)

        # Create a tree view list to list out all patients in the directory selected above
        self.open_patient_window_patients_tree = QTreeWidget()
        self.open_patient_window_patients_tree.setObjectName(
            "OpenPatientWindowPatientsTree")
        self.open_patient_window_patients_tree.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.open_patient_window_patients_tree.resize(
            self.open_patient_window_patients_tree.sizeHint().width(),
            self.open_patient_window_patients_tree.sizeHint().height())
        self.open_patient_window_patients_tree.setHeaderHidden(False)
        self.open_patient_window_patients_tree.setHeaderLabels([""])
        self.open_patient_window_patients_tree.itemChanged.connect(
            self.tree_item_changed)
        self.open_patient_window_instance_vertical_box.addWidget(
            self.open_patient_window_patients_tree)
        self.last_patient = None

        # Create a label to show what would happen if they select the patient
        self.open_patient_directory_result_label = QtWidgets.QLabel()
        self.open_patient_directory_result_label.setObjectName(
            "OpenPatientDirectoryResultLabel")
        self.open_patient_directory_result_label.setAlignment(Qt.AlignLeft)
        self.open_patient_window_instance_vertical_box.addWidget(
            self.open_patient_directory_result_label)

        # Create a horizontal box to hold the Cancel and Open button
        self.open_patient_window_patient_open_actions_horizontal_box = QHBoxLayout(
        )
        self.open_patient_window_patient_open_actions_horizontal_box.setObjectName(
            "OpenPatientWindowPatientOpenActionsHorizontalBox")
        self.open_patient_window_patient_open_actions_horizontal_box.addStretch(
            1)
        # Add a button to go back/exit from the application
        self.open_patient_window_exit_button = QPushButton()
        self.open_patient_window_exit_button.setObjectName(
            "OpenPatientWindowExitButton")
        self.open_patient_window_exit_button.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.open_patient_window_exit_button.resize(
            self.open_patient_window_stop_button.sizeHint().width(),
            self.open_patient_window_stop_button.sizeHint().height())
        self.open_patient_window_exit_button.setCursor(
            QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.open_patient_window_exit_button.clicked.connect(
            self.exit_button_clicked)
        self.open_patient_window_exit_button.setProperty(
            "QPushButtonClass", "fail-button")
        self.open_patient_window_patient_open_actions_horizontal_box.addWidget(
            self.open_patient_window_exit_button)

        # Add a button to confirm opening of the patient
        self.open_patient_window_confirm_button = QPushButton()
        self.open_patient_window_confirm_button.setObjectName(
            "OpenPatientWindowConfirmButton")
        self.open_patient_window_confirm_button.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.open_patient_window_confirm_button.resize(
            self.open_patient_window_confirm_button.sizeHint().width(),
            self.open_patient_window_confirm_button.sizeHint().height())
        self.open_patient_window_confirm_button.setCursor(
            QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.open_patient_window_confirm_button.setDisabled(True)
        self.open_patient_window_confirm_button.clicked.connect(
            self.confirm_button_clicked)
        self.open_patient_window_confirm_button.setProperty(
            "QPushButtonClass", "success-button")
        self.open_patient_window_patient_open_actions_horizontal_box.addWidget(
            self.open_patient_window_confirm_button)

        # Create a widget to house all of the actions button for open patient window
        self.open_patient_window_patient_open_actions_widget = QWidget()
        self.open_patient_window_patient_open_actions_widget.setLayout(
            self.open_patient_window_patient_open_actions_horizontal_box)
        self.open_patient_window_instance_vertical_box.addWidget(
            self.open_patient_window_patient_open_actions_widget)

        # Set the vertical box fourth element, the tree view, to stretch out as far as possible
        self.open_patient_window_instance_vertical_box.setStretch(
            3, 4)  # Stretch the treeview out as far as possible
        self.open_patient_window_instance_central_widget = QWidget()
        self.open_patient_window_instance_central_widget.setObjectName(
            "OpenPatientWindowInstanceCentralWidget")
        self.open_patient_window_instance_central_widget.setLayout(
            self.open_patient_window_instance_vertical_box)

        # Create threadpool for multithreading
        self.threadpool = QThreadPool()
        print("Multithreading with maximum %d threads" %
              self.threadpool.maxThreadCount())
        # Create interrupt event for stopping the directory search
        self.interrupt_flag = threading.Event()

        # Bind all texts into the buttons and labels
        self.retranslate_ui(open_patient_window_instance)
        # Set the central widget, ready for display
        open_patient_window_instance.setCentralWidget(
            self.open_patient_window_instance_central_widget)

        # Set the current stylesheet to the instance and connect it back to the caller through slot
        _stylesheet = open(resource_path(self.stylesheet_path)).read()
        open_patient_window_instance.setStyleSheet(_stylesheet)

        QtCore.QMetaObject.connectSlotsByName(open_patient_window_instance)

    def retranslate_ui(self, open_patient_window_instance):
        _translate = QtCore.QCoreApplication.translate
        open_patient_window_instance.setWindowTitle(
            _translate("OpenPatientWindowInstance",
                       "OnkoDICOM - Select Patient"))
        self.open_patient_directory_prompt.setText(
            _translate(
                "OpenPatientWindowInstance",
                "Choose the path of the folder containing DICOM files to load Patient's details:"
            ))
        self.open_patient_directory_input_box.setPlaceholderText(
            _translate(
                "OpenPatientWindowInstance",
                "Enter DICOM Files Path (For example, C:\path\\to\your\DICOM\Files)"
            ))
        self.open_patient_directory_choose_button.setText(
            _translate("OpenPatientWindowInstance", "Choose"))
        self.open_patient_directory_appear_prompt.setText(
            _translate(
                "OpenPatientWindowInstance",
                "Patient File directory shown below once file path chosen. Please select the file(s) you want to open:"
            ))
        self.open_patient_directory_result_label.setText(
            "The selected directory(s) above will be opened in the OnkoDICOM program."
        )
        self.open_patient_window_stop_button.setText(
            _translate("OpenPatientWindowInstance", "Stop Search"))
        self.open_patient_window_exit_button.setText(
            _translate("OpenPatientWindowInstance", "Exit"))
        self.open_patient_window_confirm_button.setText(
            _translate("OpenPatientWindowInstance", "Confirm"))

    def exit_button_clicked(self):
        QCoreApplication.exit(0)

    def scan_directory_for_patient(self):
        # Reset tree view header and last patient
        self.open_patient_window_patients_tree.setHeaderLabels([""])
        self.last_patient = None
        self.filepath = self.open_patient_directory_input_box.text()
        # Proceed if a folder was selected
        if self.filepath != "":
            # Update the QTreeWidget to reflect data being loaded
            # First, clear the widget of any existing data
            self.open_patient_window_patients_tree.clear()

            # Next, update the tree widget
            self.open_patient_window_patients_tree.addTopLevelItem(
                QTreeWidgetItem(["Loading selected directory..."]))

            # The choose button is disabled until the thread finishes executing
            self.open_patient_directory_choose_button.setEnabled(False)

            # Reveals the Stop Search button for the duration of the search
            self.open_patient_window_stop_button.setVisible(True)

            # The interrupt flag is then un-set if a previous search has been stopped.
            self.interrupt_flag.clear()

            # Then, create a new thread that will load the selected folder
            worker = Worker(DICOMDirectorySearch.get_dicom_structure,
                            self.filepath,
                            self.interrupt_flag,
                            progress_callback=True)
            worker.signals.result.connect(self.on_search_complete)
            worker.signals.progress.connect(self.search_progress)

            # Execute the thread
            self.threadpool.start(worker)

    def choose_button_clicked(self):
        """
        Executes when the choose button is clicked.
        Gets filepath from the user and loads all files and subdirectories.
        """
        # Get folder path from pop up dialog box
        self.filepath = QtWidgets.QFileDialog.getExistingDirectory(
            None, 'Select patient folder...', '')
        self.open_patient_directory_input_box.setText(self.filepath)
        self.scan_directory_for_patient()

    def stop_button_clicked(self):
        self.interrupt_flag.set()

    def search_progress(self, progress_update):
        """
        Current progress of the file search.
        """
        self.open_patient_window_patients_tree.clear()
        self.open_patient_window_patients_tree.addTopLevelItem(
            QTreeWidgetItem([
                "Loading selected directory... (%s files searched)" %
                progress_update
            ]))

    def on_search_complete(self, dicom_structure):
        """
        Executes once the directory search is complete.
        :param dicom_structure: DICOMStructure object constructed by the directory search.
        """
        self.open_patient_directory_choose_button.setEnabled(True)
        self.open_patient_window_stop_button.setVisible(False)
        self.open_patient_window_patients_tree.clear()

        if dicom_structure is None:  # dicom_structure will be None if function was interrupted.
            return

        for patient_item in dicom_structure.get_tree_items_list():
            self.open_patient_window_patients_tree.addTopLevelItem(
                patient_item)

        if len(dicom_structure.patients) == 0:
            QMessageBox.about(self, "No files found",
                              "Selected directory contains no DICOM files.")

    def tree_item_changed(self, item, _):
        """
            Executes when a tree item is checked or unchecked.
            If a different patient is checked, uncheck the previous patient.
            Inform user about missing DICOM files.
        """
        selected_patient = item
        # If the item is not top-level, bubble up to see which top-level item this item belongs to
        if self.open_patient_window_patients_tree.invisibleRootItem(
        ).indexOfChild(item) == -1:
            while self.open_patient_window_patients_tree.invisibleRootItem(
            ).indexOfChild(selected_patient) == -1:
                selected_patient = selected_patient.parent()

        # Uncheck previous patient if a different patient is selected
        if item.checkState(
                0
        ) == Qt.CheckState.Checked and self.last_patient != selected_patient:
            if self.last_patient is not None:
                self.last_patient.setCheckState(0, Qt.CheckState.Unchecked)
                self.last_patient.setSelected(False)
            self.last_patient = selected_patient

        # Get the types of all selected leaves
        self.selected_series_types = set()
        for checked_item in self.get_checked_leaves():
            series_type = checked_item.dicom_object.get_series_type()
            if type(series_type) == str:
                self.selected_series_types.add(series_type)
            else:
                self.selected_series_types.update(series_type)

        # Check the existence of IMAGE, RTSTRUCT and RTDOSE files
        if len(list({'CT', 'MR', 'PT'} & self.selected_series_types)) == 0:
            header = "Cannot proceed without an image file."
            self.open_patient_window_confirm_button.setDisabled(True)
        elif 'RTSTRUCT' not in self.selected_series_types:
            header = "DVH and Radiomics calculations are not available without a RTSTRUCT file."
        elif 'RTDOSE' not in self.selected_series_types:
            header = "DVH calculations are not available without a RTDOSE file."
        else:
            header = ""
        self.open_patient_window_patients_tree.setHeaderLabel(header)

        if len(list({'CT', 'MR', 'PT'} & self.selected_series_types)) != 0:
            self.open_patient_window_confirm_button.setDisabled(False)

    def confirm_button_clicked(self):
        """
        Begins loading of the selected files.
        """
        selected_files = []
        for item in self.get_checked_leaves():
            selected_files += item.dicom_object.get_files()

        self.progress_window = ProgressWindow(
            self, QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowCloseButtonHint)
        self.progress_window.signal_loaded.connect(self.on_loaded)
        self.progress_window.signal_error.connect(self.on_loading_error)

        self.progress_window.start_loading(selected_files)
        self.progress_window.exec_()

    def on_loaded(self, results):
        """
        Executes when the progress bar finishes loaded the selected files.
        """
        if results[0] is True:  # Will be NoneType if loading was interrupted.
            self.patient_info_initialized.emit(
                results[1])  # Emits the progress window.

    def on_loading_error(self, error_code):
        """
        Error handling for progress window.
        """
        if error_code == 0:
            QMessageBox.about(
                self.progress_window, "Unable to open selection",
                "Selected files cannot be opened as they are not a DICOM-RT set."
            )
            self.progress_window.close()
        elif error_code == 1:
            QMessageBox.about(
                self.progress_window, "Unable to open selection",
                "Selected files cannot be opened as they contain unsupported DICOM classes."
            )
            self.progress_window.close()

    def get_checked_leaves(self):
        """
        :return: A list of all QTreeWidgetItems in the QTreeWidget that are both leaves and checked.
        """
        checked_items = []

        def recurse(parent_item: QTreeWidgetItem):
            for i in range(parent_item.childCount()):
                child = parent_item.child(i)
                grand_children = child.childCount()
                if grand_children > 0:
                    recurse(child)
                else:
                    if child.checkState(0) == Qt.Checked:
                        checked_items.append(child)

        recurse(self.open_patient_window_patients_tree.invisibleRootItem())
        return checked_items
Beispiel #5
0
class Ui_Form(object):
    def setupUi(self, Form):
        if not Form.objectName():
            Form.setObjectName(u"Form")
        Form.resize(600, 500)
        Form.setStyleSheet(u"QWidget#Form{\n"
                           "	background-color: rgb(225, 243, 254);\n"
                           "}")
        self.verticalLayout_2 = QVBoxLayout(Form)
        self.verticalLayout_2.setObjectName(u"verticalLayout_2")
        self.horizontalLayout_2 = QHBoxLayout()
        self.horizontalLayout_2.setSpacing(6)
        self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
        self.lineEdit_headers_path = HeaderFileQLineEdit(Form)
        self.lineEdit_headers_path.setObjectName(u"lineEdit_headers_path")
        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.lineEdit_headers_path.sizePolicy().hasHeightForWidth())
        self.lineEdit_headers_path.setSizePolicy(sizePolicy)

        self.horizontalLayout_2.addWidget(self.lineEdit_headers_path)

        self.pushButton_select = QPushButton(Form)
        self.pushButton_select.setObjectName(u"pushButton_select")
        sizePolicy1 = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)
        sizePolicy1.setHorizontalStretch(0)
        sizePolicy1.setVerticalStretch(0)
        sizePolicy1.setHeightForWidth(
            self.pushButton_select.sizePolicy().hasHeightForWidth())
        self.pushButton_select.setSizePolicy(sizePolicy1)
        self.pushButton_select.setMaximumSize(QSize(16777215, 40))

        self.horizontalLayout_2.addWidget(self.pushButton_select)

        self.verticalLayout_2.addLayout(self.horizontalLayout_2)

        self.horizontalLayout = QHBoxLayout()
        self.horizontalLayout.setSpacing(6)
        self.horizontalLayout.setObjectName(u"horizontalLayout")
        self.textEdit_headers_content = HeadersQTextEdit(Form)
        self.textEdit_headers_content.setObjectName(
            u"textEdit_headers_content")

        self.horizontalLayout.addWidget(self.textEdit_headers_content)

        self.verticalLayout = QVBoxLayout()
        self.verticalLayout.setSpacing(6)
        self.verticalLayout.setObjectName(u"verticalLayout")
        self.pushButton_save = QPushButton(Form)
        self.pushButton_save.setObjectName(u"pushButton_save")
        sizePolicy1.setHeightForWidth(
            self.pushButton_save.sizePolicy().hasHeightForWidth())
        self.pushButton_save.setSizePolicy(sizePolicy1)
        self.pushButton_save.setMaximumSize(QSize(16777215, 40))

        self.verticalLayout.addWidget(self.pushButton_save)

        self.pushButton_add = QPushButton(Form)
        self.pushButton_add.setObjectName(u"pushButton_add")
        sizePolicy1.setHeightForWidth(
            self.pushButton_add.sizePolicy().hasHeightForWidth())
        self.pushButton_add.setSizePolicy(sizePolicy1)
        self.pushButton_add.setMaximumSize(QSize(16777215, 40))

        self.verticalLayout.addWidget(self.pushButton_add)

        self.horizontalLayout.addLayout(self.verticalLayout)

        self.verticalLayout_2.addLayout(self.horizontalLayout)

        self.horizontalLayout_3 = QHBoxLayout()
        self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
        self.listWidget_headers_key = QListWidget(Form)
        self.listWidget_headers_key.setObjectName(u"listWidget_headers_key")

        self.horizontalLayout_3.addWidget(self.listWidget_headers_key)

        self.listWidget_headers_value = QListWidget(Form)
        self.listWidget_headers_value.setObjectName(
            u"listWidget_headers_value")

        self.horizontalLayout_3.addWidget(self.listWidget_headers_value)

        self.horizontalLayout_3.setStretch(0, 1)
        self.horizontalLayout_3.setStretch(1, 4)

        self.verticalLayout_2.addLayout(self.horizontalLayout_3)

        self.verticalLayout_2.setStretch(0, 1)
        self.verticalLayout_2.setStretch(1, 3)
        self.verticalLayout_2.setStretch(2, 6)

        self.retranslateUi(Form)

        QMetaObject.connectSlotsByName(Form)

    # setupUi

    def retranslateUi(self, Form):
        Form.setWindowTitle(
            QCoreApplication.translate("Form", u"headers editor", None))
        self.lineEdit_headers_path.setPlaceholderText(
            QCoreApplication.translate("Form", u"headers.json", None))
        #if QT_CONFIG(tooltip)
        self.pushButton_select.setToolTip(
            QCoreApplication.translate(
                "Form",
                u"<html><head/><body><p>load headers.json file</p></body></html>",
                None))
        #endif // QT_CONFIG(tooltip)
        self.pushButton_select.setText(
            QCoreApplication.translate("Form", u"select", None))
        #if QT_CONFIG(tooltip)
        self.pushButton_save.setToolTip(
            QCoreApplication.translate(
                "Form",
                u"<html><head/><body><p>save to headers.json</p></body></html>",
                None))
        #endif // QT_CONFIG(tooltip)
        self.pushButton_save.setText(
            QCoreApplication.translate("Form", u"save", None))
        #if QT_CONFIG(tooltip)
        self.pushButton_add.setToolTip(
            QCoreApplication.translate(
                "Form",
                u"<html><head/><body><p>add a group of header key-value</p></body></html>",
                None))
        #endif // QT_CONFIG(tooltip)
        self.pushButton_add.setText(
            QCoreApplication.translate("Form", u"add", None))
class UIDeleteROIWindow():
    def setup_ui(self, delete_roi_window_instance, regions_of_interest,
                 dataset_rtss, deleting_rois_structure_tuple):
        # Initialise the 2 lists for containing the ROI(s) that we are going to keep and delete respectively
        self.regions_of_interest_to_keep = []
        self.regions_of_interest_to_delete = []
        # This is for holding the original list of ROI(s)
        self.regions_of_interest_list = regions_of_interest
        # This is for holding the DICOM dataset of that specific patient
        self.dataset_rtss = dataset_rtss
        # Assigning new tuple for holding the deleting ROI(s)
        self.deleting_rois_structure_tuple = deleting_rois_structure_tuple

        # Initialise a DeleteROIWindow
        if platform.system() == 'Darwin':
            self.stylesheet_path = "res/stylesheet.qss"
        else:
            self.stylesheet_path = "res/stylesheet-win-linux.qss"
        stylesheet = open(resource_path(self.stylesheet_path)).read()
        window_icon = QIcon()
        window_icon.addPixmap(QPixmap(resource_path("res/images/icon.ico")),
                              QIcon.Normal, QIcon.Off)
        delete_roi_window_instance.setObjectName("DeleteRoiWindowInstance")
        delete_roi_window_instance.setWindowIcon(window_icon)
        delete_roi_window_instance.resize(800, 606)

        # Create a vertical box to hold all widgets
        self.delete_roi_window_instance_vertical_box = QVBoxLayout()
        self.delete_roi_window_instance_vertical_box.setObjectName(
            "DeleteRoiWindowInstanceVerticalBox")

        # Create a label for holding the window's title
        self.delete_roi_window_title = QLabel()
        self.delete_roi_window_title.setObjectName("DeleteRoiWindowTitle")
        self.delete_roi_window_title.setProperty("QLabelClass", "window-title")
        self.delete_roi_window_title.setAlignment(Qt.AlignLeft)
        self.delete_roi_window_instance_vertical_box.addWidget(
            self.delete_roi_window_title)

        # Create a label for holding the instruction of how to delete the ROIs
        self.delete_roi_window_instruction = QLabel()
        self.delete_roi_window_instruction.setObjectName(
            "DeleteRoiWindowInstruction")
        self.delete_roi_window_instruction.setAlignment(Qt.AlignCenter)
        self.delete_roi_window_instance_vertical_box.addWidget(
            self.delete_roi_window_instruction)

        # Create a horizontal box for holding the 2 lists and the move left, move right buttons
        self.delete_roi_window_keep_and_delete_box = QHBoxLayout()
        self.delete_roi_window_keep_and_delete_box.setObjectName(
            "DeleteRoiWindowKeepAndDeleteBox")
        # ================================= KEEP BOX =================================
        # Create a vertical box for holding the label and the tree view for holding the ROIs that we are keeping
        self.delete_roi_window_keep_vertical_box = QVBoxLayout()
        self.delete_roi_window_keep_vertical_box.setObjectName(
            "DeleteRoiWindowKeepVerticalBox")
        # Create a label for the tree view with the list of ROIs to keep
        self.delete_roi_window_keep_tree_view_label = QLabel()
        self.delete_roi_window_keep_tree_view_label.setObjectName(
            "DeleteRoiWindowKeepTreeViewLabel")
        self.delete_roi_window_keep_tree_view_label.setProperty(
            "QLabelClass", ["tree-view-label", "tree-view-label-keep-delete"])
        self.delete_roi_window_keep_tree_view_label.setAlignment(
            Qt.AlignCenter)
        self.delete_roi_window_keep_tree_view_label.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.delete_roi_window_keep_tree_view_label.resize(
            self.delete_roi_window_keep_tree_view_label.sizeHint().width(),
            self.delete_roi_window_keep_tree_view_label.sizeHint().height())
        self.delete_roi_window_keep_vertical_box.addWidget(
            self.delete_roi_window_keep_tree_view_label)
        # Create a tree view for containing the list of ROIs to keep
        self.delete_roi_window_keep_tree_view = QTreeWidget()
        self.delete_roi_window_keep_tree_view.setObjectName(
            "DeleteRoiWindowKeepTreeView")
        self.delete_roi_window_keep_tree_view.setHeaderHidden(True)
        self.delete_roi_window_keep_tree_view.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.delete_roi_window_keep_tree_view.resize(
            self.delete_roi_window_keep_tree_view.sizeHint().width(),
            self.delete_roi_window_keep_tree_view.sizeHint().height())
        self.delete_roi_window_keep_vertical_box.addWidget(
            self.delete_roi_window_keep_tree_view)
        self.delete_roi_window_keep_vertical_box.setStretch(1, 4)
        # Create a widget to hold the keep vertical box
        self.delete_roi_window_keep_widget = QWidget()
        self.delete_roi_window_keep_widget.setObjectName(
            "DeleteRoiWindowKeepWidget")
        self.delete_roi_window_keep_widget.setLayout(
            self.delete_roi_window_keep_vertical_box)
        self.delete_roi_window_keep_and_delete_box.addStretch(1)
        self.delete_roi_window_keep_and_delete_box.addWidget(
            self.delete_roi_window_keep_widget)
        # ================================= KEEP BOX =================================

        # ================================= MOVE LEFT/RIGHT BOX =================================
        # Create a vertical box for holding the 2 buttons for moving left and right
        self.delete_roi_window_move_left_right_vertical_box = QVBoxLayout()
        self.delete_roi_window_move_left_right_vertical_box.setObjectName(
            "DeleteRoiWindowMoveLeftRightVerticalBox")
        # Create Move Right Button / Delete Button
        self.move_right_button = QPushButton()
        self.move_right_button.setObjectName("MoveRightButton")
        self.move_right_button.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.move_right_button.resize(
            self.move_right_button.sizeHint().width(),
            self.move_right_button.sizeHint().height())
        self.move_right_button.setCursor(
            QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.move_right_button.clicked.connect(
            self.move_right_button_onClicked)
        self.move_right_button.setProperty("QPushButtonClass", "fail-button")
        self.delete_roi_window_move_left_right_vertical_box.addStretch(1)
        self.delete_roi_window_move_left_right_vertical_box.addWidget(
            self.move_right_button)
        # Create Move Left Button / Keep Button
        self.move_left_button = QPushButton()
        self.move_left_button.setObjectName("MoveLeftButton")
        self.move_left_button.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.move_left_button.resize(self.move_left_button.sizeHint().width(),
                                     self.move_left_button.sizeHint().height())
        self.move_left_button.setCursor(
            QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.move_left_button.clicked.connect(self.move_left_button_onClicked)
        self.move_left_button.setProperty("QPushButtonClass", "success-button")
        self.delete_roi_window_move_left_right_vertical_box.addWidget(
            self.move_left_button)
        self.delete_roi_window_move_left_right_vertical_box.addStretch(1)
        # Create a widget for holding the 2 buttons
        self.delete_roi_window_move_left_right_widget = QWidget()
        self.delete_roi_window_move_left_right_widget.setObjectName(
            "DeleteRoiWindowMoveLeftRightWidget")
        self.delete_roi_window_move_left_right_widget.setLayout(
            self.delete_roi_window_move_left_right_vertical_box)
        self.delete_roi_window_keep_and_delete_box.addWidget(
            self.delete_roi_window_move_left_right_widget)
        # ================================= MOVE LEFT/RIGHT BOX =================================

        # ================================= DELETE BOX =================================
        # Create a vertical box for holding the label and the tree view for holding the ROIs that we are deleting
        self.delete_roi_window_delete_vertical_box = QVBoxLayout()
        self.delete_roi_window_delete_vertical_box.setObjectName(
            "DeleteRoiWindowDeleteVerticalBox")
        # Create a label for the tree view with the list of ROIs to delete
        self.delete_roi_window_delete_tree_view_label = QLabel()
        self.delete_roi_window_delete_tree_view_label.setObjectName(
            "DeleteRoiWindowDeleteTreeViewLabel")
        self.delete_roi_window_delete_tree_view_label.setProperty(
            "QLabelClass", ["tree-view-label", "tree-view-label-keep-delete"])
        self.delete_roi_window_delete_tree_view_label.setAlignment(
            Qt.AlignCenter)
        self.delete_roi_window_delete_tree_view_label.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.delete_roi_window_delete_tree_view_label.resize(
            self.delete_roi_window_delete_tree_view_label.sizeHint().width(),
            self.delete_roi_window_delete_tree_view_label.sizeHint().height())
        self.delete_roi_window_delete_vertical_box.addWidget(
            self.delete_roi_window_delete_tree_view_label)
        # Create a tree view for containing the list of ROIs to delete
        self.delete_roi_window_delete_tree_view = QTreeWidget()
        self.delete_roi_window_delete_tree_view.setObjectName(
            "DeleteRoiWindowDeleteTreeView")
        self.delete_roi_window_delete_tree_view.setHeaderHidden(True)
        self.delete_roi_window_delete_tree_view.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.delete_roi_window_delete_tree_view.resize(
            self.delete_roi_window_delete_tree_view.sizeHint().width(),
            self.delete_roi_window_delete_tree_view.sizeHint().height())
        self.delete_roi_window_delete_vertical_box.addWidget(
            self.delete_roi_window_delete_tree_view)
        self.delete_roi_window_delete_vertical_box.setStretch(1, 4)
        # Create a widget to hold the delete vertical box
        self.delete_roi_window_delete_widget = QWidget()
        self.delete_roi_window_delete_widget.setObjectName(
            "DeleteRoiWindowDeleteWidget")
        self.delete_roi_window_delete_widget.setLayout(
            self.delete_roi_window_delete_vertical_box)
        self.delete_roi_window_keep_and_delete_box.addWidget(
            self.delete_roi_window_delete_widget)
        self.delete_roi_window_keep_and_delete_box.addStretch(1)
        self.delete_roi_window_keep_and_delete_box.setStretch(1, 4)
        self.delete_roi_window_keep_and_delete_box.setStretch(3, 4)
        # ================================= DELETE BOX =================================
        # Create a widget to hold the keep and delete box
        self.delete_roi_window_keep_and_delete_widget = QWidget()
        self.delete_roi_window_keep_and_delete_widget.setObjectName(
            "DeleteRoiWindowKeepAndDeleteWidget")
        self.delete_roi_window_keep_and_delete_widget.setLayout(
            self.delete_roi_window_keep_and_delete_box)
        self.delete_roi_window_instance_vertical_box.addWidget(
            self.delete_roi_window_keep_and_delete_widget)

        # Create a horizontal box to hold 2 action buttons for this window
        self.delete_roi_window_action_buttons_box = QHBoxLayout()
        self.delete_roi_window_action_buttons_box.setObjectName(
            "DeleteRoiWindowActionButtonsBox")
        # Create the cancel button
        self.delete_roi_window_cancel_button = QPushButton()
        self.delete_roi_window_cancel_button.setObjectName(
            "DeleteRoiWindowCancelButton")
        self.delete_roi_window_cancel_button.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.delete_roi_window_cancel_button.resize(
            self.delete_roi_window_cancel_button.sizeHint().width(),
            self.delete_roi_window_cancel_button.sizeHint().height())
        self.delete_roi_window_cancel_button.setCursor(
            QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.delete_roi_window_cancel_button.clicked.connect(
            self.on_cancel_button_clicked)
        self.delete_roi_window_cancel_button.setProperty(
            "QPushButtonClass", "fail-button")
        self.delete_roi_window_action_buttons_box.addStretch(1)
        self.delete_roi_window_action_buttons_box.addWidget(
            self.delete_roi_window_cancel_button)
        # Create the confirm button
        self.delete_roi_window_confirm_button = QPushButton()
        self.delete_roi_window_confirm_button.setObjectName(
            "DeleteRoiWindowConfirmButton")
        self.delete_roi_window_confirm_button.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.delete_roi_window_confirm_button.resize(
            self.delete_roi_window_confirm_button.sizeHint().width(),
            self.delete_roi_window_confirm_button.sizeHint().height())
        self.delete_roi_window_confirm_button.setCursor(
            QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.delete_roi_window_confirm_button.clicked.connect(
            self.confirm_button_onClicked)
        self.delete_roi_window_confirm_button.setEnabled(False)
        self.delete_roi_window_confirm_button.setProperty(
            "QPushButtonClass", "success-button")
        self.delete_roi_window_action_buttons_box.addWidget(
            self.delete_roi_window_confirm_button)
        # Create a widget to hold the action buttons
        self.delete_roi_window_action_buttons_widget = QWidget()
        self.delete_roi_window_action_buttons_widget.setObjectName(
            "DeleteRoiWindowActionButtonsWidget")
        self.delete_roi_window_action_buttons_widget.setLayout(
            self.delete_roi_window_action_buttons_box)
        self.delete_roi_window_instance_vertical_box.addWidget(
            self.delete_roi_window_action_buttons_widget)

        # Set text for all attributes
        self.retranslate_ui(delete_roi_window_instance)
        # Create a central widget to hold the vertical layout box
        self.delete_roi_window_instance_central_widget = QWidget()
        self.delete_roi_window_instance_central_widget.setObjectName(
            "DeleteRoiWindowInstanceCentralWidget")
        self.delete_roi_window_instance_central_widget.setLayout(
            self.delete_roi_window_instance_vertical_box)
        self.delete_roi_window_instance_vertical_box.setStretch(2, 4)
        # Set the central widget for the main window and style the window
        delete_roi_window_instance.setCentralWidget(
            self.delete_roi_window_instance_central_widget)
        delete_roi_window_instance.setStyleSheet(stylesheet)

        # Load the ROIs in
        self.display_rois_in_listViewKeep()
        # Set the selection mode to multi so that we can select multiple ROIs to delete
        self.delete_roi_window_keep_tree_view.setSelectionMode(
            QAbstractItemView.MultiSelection)
        self.delete_roi_window_delete_tree_view.setSelectionMode(
            QAbstractItemView.MultiSelection)

        QtCore.QMetaObject.connectSlotsByName(delete_roi_window_instance)

    def retranslate_ui(self, delete_roi_window_instance):
        _translate = QtCore.QCoreApplication.translate
        delete_roi_window_instance.setWindowTitle(
            _translate("DeleteRoiWindowInstance", "OnkoDICOM - Delete ROI(s)"))
        self.delete_roi_window_title.setText(
            _translate("DeleteRoiWindowTitle", "Delete ROI(s)"))
        self.delete_roi_window_instruction.setText(
            _translate(
                "DeleteRoiWindowInstruction",
                "Move the Regions of Interest to be deleted to the right-hand side or vice versa"
            ))
        self.delete_roi_window_keep_tree_view_label.setText(
            _translate("DeleteRoiWindowKeepTreeViewLabel", "To Keep"))
        self.delete_roi_window_delete_tree_view_label.setText(
            _translate("DeleteRoiWindowDeleteTreeViewLabel", "To Delete"))
        self.move_right_button.setText(
            _translate("MoveRightButton", "Move Right ->>>"))
        self.move_left_button.setText(
            _translate("MoveLeftButton", "<<<- Move Left"))
        self.delete_roi_window_cancel_button.setText(
            _translate("DeleteRoiWindowCancelButton", "Cancel"))
        self.delete_roi_window_confirm_button.setText(
            _translate("DeleteRoiWindowConfirmButton", "Confirm"))

    def on_cancel_button_clicked(self):
        self.close()

    def display_rois_in_listViewKeep(self):
        self.regions_of_interest_to_keep.clear()
        for roi_id, roi_dict in self.regions_of_interest_list.items():
            self.regions_of_interest_to_keep.append(roi_dict['name'])

        self.delete_roi_window_keep_tree_view.clear()
        self.delete_roi_window_keep_tree_view.setIndentation(0)

        self.item = QTreeWidgetItem(["item"])
        for index in self.regions_of_interest_to_keep:
            item = QTreeWidgetItem([index])
            self.delete_roi_window_keep_tree_view.addTopLevelItem(item)

    def move_right_button_onClicked(self):
        root_item = self.delete_roi_window_keep_tree_view.invisibleRootItem()
        for index in range(root_item.childCount()):
            item = root_item.child(index)
            if item in self.delete_roi_window_keep_tree_view.selectedItems():
                # This will get ROI name
                self.regions_of_interest_to_delete.append(item.text(0))

        # Move to the right column list
        self.delete_roi_window_delete_tree_view.clear()
        self.delete_roi_window_delete_tree_view.setIndentation(0)
        for roi in self.regions_of_interest_to_delete:
            item = QTreeWidgetItem([roi])
            self.delete_roi_window_delete_tree_view.addTopLevelItem(item)
            self.delete_roi_window_confirm_button.setEnabled(True)

        # Delete moved items from the left column list
        self.regions_of_interest_to_keep = [
            x for x in self.regions_of_interest_to_keep
            if x not in self.regions_of_interest_to_delete
        ]

        self.delete_roi_window_keep_tree_view.clear()
        for index in self.regions_of_interest_to_keep:
            item = QTreeWidgetItem([index])
            self.delete_roi_window_keep_tree_view.addTopLevelItem(item)

    def move_left_button_onClicked(self):
        root_item = self.delete_roi_window_delete_tree_view.invisibleRootItem()

        for index in range(root_item.childCount()):
            item = root_item.child(index)
            if item in self.delete_roi_window_delete_tree_view.selectedItems():
                # This will get ROI name
                self.regions_of_interest_to_keep.append(item.text(0))

        # Move to the left column list
        self.delete_roi_window_keep_tree_view.clear()
        self.delete_roi_window_keep_tree_view.setIndentation(0)
        for roi in self.regions_of_interest_to_keep:
            item = QTreeWidgetItem([roi])
            self.delete_roi_window_keep_tree_view.addTopLevelItem(item)

        # Delete moved items from the right column list
        self.regions_of_interest_to_delete = [
            x for x in self.regions_of_interest_to_delete
            if x not in self.regions_of_interest_to_keep
        ]

        self.delete_roi_window_delete_tree_view.clear()
        for index in self.regions_of_interest_to_delete:
            item = QTreeWidgetItem([index])
            self.delete_roi_window_delete_tree_view.addTopLevelItem(item)

        if len(self.regions_of_interest_to_delete) == 0:
            self.delete_roi_window_confirm_button.setEnabled(False)

    def confirm_button_onClicked(self):
        confirmation_dialog = QMessageBox.information(
            self, 'Delete ROI(s)?',
            'Region(s) of Interest in the To Delete table will be deleted. '
            'Would you like to continue?', QMessageBox.Yes | QMessageBox.No)
        if confirmation_dialog == QMessageBox.Yes:
            progress_window = DeleteROIProgressWindow(
                self, QtCore.Qt.WindowTitleHint)
            progress_window.signal_roi_deleted.connect(self.on_rois_deleted)
            progress_window.start_deleting(self.dataset_rtss,
                                           self.regions_of_interest_to_delete)
            progress_window.show()

    def on_rois_deleted(self, new_rtss):
        self.deleting_rois_structure_tuple.emit((new_rtss, {
            "delete":
            self.regions_of_interest_to_delete
        }))
        QMessageBox.about(self, "Saved",
                          "Regions of interest successfully deleted!")
        self.close()
Beispiel #7
0
class Ui_testGlWindow(object):
    def setupUi(self, testGlWindow):
        if not testGlWindow.objectName():
            testGlWindow.setObjectName(u"testGlWindow")
        testGlWindow.resize(952, 847)
        testGlWindow.setAcceptDrops(True)
        icon = QIcon()
        icon.addFile(u":/images/candle_256.png", QSize(), QIcon.Normal,
                     QIcon.Off)
        testGlWindow.setWindowIcon(icon)
        testGlWindow.setStyleSheet(u"")
        self.centralWidget = QWidget(testGlWindow)
        self.centralWidget.setObjectName(u"centralWidget")
        self.horizontalLayout_5 = QHBoxLayout(self.centralWidget)
        self.horizontalLayout_5.setSpacing(9)
        self.horizontalLayout_5.setContentsMargins(11, 11, 11, 11)
        self.horizontalLayout_5.setObjectName(u"horizontalLayout_5")
        self.horizontalLayout_5.setContentsMargins(9, 9, 5, 9)
        self.grpProgram = QGroupBox(self.centralWidget)
        self.grpProgram.setObjectName(u"grpProgram")
        self.grpProgram.setFlat(False)
        self.verticalLayout_17 = QVBoxLayout(self.grpProgram)
        self.verticalLayout_17.setSpacing(7)
        self.verticalLayout_17.setContentsMargins(11, 11, 11, 11)
        self.verticalLayout_17.setObjectName(u"verticalLayout_17")
        self.verticalLayout_17.setContentsMargins(8, 8, 8, 8)
        self.splitter = QSplitter(self.grpProgram)
        self.splitter.setObjectName(u"splitter")
        self.splitter.setOrientation(Qt.Vertical)
        self.splitter.setHandleWidth(12)
        self.frame = QWidget(self.splitter)
        self.frame.setObjectName(u"frame")
        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.frame.sizePolicy().hasHeightForWidth())
        self.frame.setSizePolicy(sizePolicy)
        self.frame.setMinimumSize(QSize(0, 600))
        self.frame.setStyleSheet(u"border: 1px solid gray;")
        self.verticalLayout_8 = QVBoxLayout(self.frame)
        self.verticalLayout_8.setSpacing(6)
        self.verticalLayout_8.setContentsMargins(11, 11, 11, 11)
        self.verticalLayout_8.setObjectName(u"verticalLayout_8")
        self.verticalLayout_8.setContentsMargins(1, 1, 1, 1)
        self.splitter.addWidget(self.frame)
        self.layoutWidget = QWidget(self.splitter)
        self.layoutWidget.setObjectName(u"layoutWidget")
        self.verticalLayout_7 = QVBoxLayout(self.layoutWidget)
        self.verticalLayout_7.setSpacing(9)
        self.verticalLayout_7.setContentsMargins(11, 11, 11, 11)
        self.verticalLayout_7.setObjectName(u"verticalLayout_7")
        self.verticalLayout_7.setContentsMargins(0, 0, 0, 0)
        self.tblProgram = QTableView(self.layoutWidget)
        self.tblProgram.setObjectName(u"tblProgram")
        font = QFont()
        font.setPointSize(9)
        self.tblProgram.setFont(font)
        self.tblProgram.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tblProgram.setEditTriggers(QAbstractItemView.AnyKeyPressed
                                        | QAbstractItemView.DoubleClicked
                                        | QAbstractItemView.EditKeyPressed
                                        | QAbstractItemView.SelectedClicked)
        self.tblProgram.setSelectionMode(QAbstractItemView.ContiguousSelection)
        self.tblProgram.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.tblProgram.setGridStyle(Qt.DashLine)
        self.tblProgram.horizontalHeader().setMinimumSectionSize(50)
        self.tblProgram.horizontalHeader().setHighlightSections(False)
        self.tblProgram.verticalHeader().setVisible(False)

        self.verticalLayout_7.addWidget(self.tblProgram)

        self.splitter.addWidget(self.layoutWidget)

        self.verticalLayout_17.addWidget(self.splitter)

        self.verticalLayout_17.setStretch(0, 1)

        self.horizontalLayout_5.addWidget(self.grpProgram)

        self.horizontalLayout_5.setStretch(0, 100)
        testGlWindow.setCentralWidget(self.centralWidget)
        self.menuBar = QMenuBar(testGlWindow)
        self.menuBar.setObjectName(u"menuBar")
        self.menuBar.setGeometry(QRect(0, 0, 952, 21))
        testGlWindow.setMenuBar(self.menuBar)

        self.retranslateUi(testGlWindow)

        QMetaObject.connectSlotsByName(testGlWindow)

    # setupUi

    def retranslateUi(self, testGlWindow):
        testGlWindow.setWindowTitle(
            QCoreApplication.translate("testGlWindow", u"Candle", None))
        self.grpProgram.setTitle(
            QCoreApplication.translate("testGlWindow", u"G-code program",
                                       None))
Beispiel #8
0
class UIImageFusionWindow(object):
    image_fusion_info_initialized = QtCore.Signal(object)

    def setup_ui(self, open_image_fusion_select_instance):
        """Sets up a UI"""
        if platform.system() == 'Darwin':
            self.stylesheet_path = "res/stylesheet.qss"
        else:
            self.stylesheet_path = "res/stylesheet-win-linux.qss"

        window_icon = QIcon()
        window_icon.addPixmap(QPixmap(resource_path("res/images/icon.ico")),
                              QIcon.Normal, QIcon.Off)
        open_image_fusion_select_instance.setObjectName(
            "OpenPatientWindowInstance")
        open_image_fusion_select_instance.setWindowIcon(window_icon)
        open_image_fusion_select_instance.resize(840, 530)

        # Create a vertical box for containing the other elements and layouts
        self.open_patient_window_instance_vertical_box = QVBoxLayout()
        self.open_patient_window_instance_vertical_box.setObjectName(
            "OpenPatientWindowInstanceVerticalBox")

        # Create a label to prompt the user to enter the path to the
        # directory that contains the DICOM files
        self.open_patient_directory_prompt = QLabel()
        self.open_patient_directory_prompt.setObjectName(
            "OpenPatientDirectoryPrompt")
        self.open_patient_directory_prompt.setAlignment(Qt.AlignLeft)
        self.open_patient_window_instance_vertical_box.addWidget(
            self.open_patient_directory_prompt)

        # Create a horizontal box to hold the input box for the directory 
        # and the choose button
        self.open_patient_directory_input_horizontal_box = QHBoxLayout()
        self.open_patient_directory_input_horizontal_box.setObjectName(
            "OpenPatientDirectoryInputHorizontalBox")
        # Create a textbox to contain the path to the directory that contains 
        # the DICOM files
        self.open_patient_directory_input_box = \
            UIImageFusionWindowDragAndDropEvent(self)

        self.open_patient_directory_input_box.setObjectName(
            "OpenPatientDirectoryInputBox")
        self.open_patient_directory_input_box.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.open_patient_directory_input_box.returnPressed.connect(
            self.scan_directory_for_patient)
        self.open_patient_directory_input_horizontal_box.addWidget(
            self.open_patient_directory_input_box)

        # Create a choose button to open the file dialog
        self.open_patient_directory_choose_button = QPushButton()
        self.open_patient_directory_choose_button.setObjectName(
            "OpenPatientDirectoryChooseButton")
        self.open_patient_directory_choose_button.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.open_patient_directory_choose_button.resize(
            self.open_patient_directory_choose_button.sizeHint().width(),
            self.open_patient_directory_input_box.height())
        self.open_patient_directory_choose_button.setCursor(
            QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.open_patient_directory_input_horizontal_box.addWidget(
            self.open_patient_directory_choose_button)
        self.open_patient_directory_choose_button.clicked.connect(
            self.choose_button_clicked)

        # Create a widget to hold the input fields
        self.open_patient_directory_input_widget = QWidget()
        self.open_patient_directory_input_horizontal_box.setStretch(0, 4)
        self.open_patient_directory_input_widget.setLayout(
            self.open_patient_directory_input_horizontal_box)
        self.open_patient_window_instance_vertical_box.addWidget(
            self.open_patient_directory_input_widget)

        # Create a horizontal box to hold the stop button and direction to 
        # the user on where to select the patient
        self.open_patient_appear_prompt_and_stop_horizontal_box = QHBoxLayout()
        self.open_patient_appear_prompt_and_stop_horizontal_box.setObjectName(
            "OpenPatientAppearPromptAndStopHorizontalBox")
        # Create a label to show direction on where the files will appear
        self.open_patient_directory_appear_prompt = QLabel()
        self.open_patient_directory_appear_prompt.setObjectName(
            "OpenPatientDirectoryAppearPrompt")
        self.open_patient_directory_appear_prompt.setAlignment(Qt.AlignLeft)
        self.open_patient_appear_prompt_and_stop_horizontal_box.addWidget(
            self.open_patient_directory_appear_prompt)
        self.open_patient_appear_prompt_and_stop_horizontal_box.addStretch(1)
        # Create a button to stop searching
        self.open_patient_window_stop_button = QPushButton()
        self.open_patient_window_stop_button.setObjectName(
            "OpenPatientWindowStopButton")
        self.open_patient_window_stop_button.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.open_patient_window_stop_button.resize(
            self.open_patient_window_stop_button.sizeHint().width(),
            self.open_patient_window_stop_button.sizeHint().height())
        self.open_patient_window_stop_button.setCursor(
            QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.open_patient_window_stop_button.clicked.connect(
            self.stop_button_clicked)
        self.open_patient_window_stop_button.setProperty(
            "QPushButtonClass", "fail-button")
        self.open_patient_window_stop_button.setVisible(False)
        self.open_patient_appear_prompt_and_stop_horizontal_box.addWidget(
            self.open_patient_window_stop_button)
        # Create a widget to hold the layout
        self.open_patient_appear_prompt_and_stop_widget = QWidget()
        self.open_patient_appear_prompt_and_stop_widget.setLayout(
            self.open_patient_appear_prompt_and_stop_horizontal_box)
        self.open_patient_window_instance_vertical_box.addWidget(
            self.open_patient_appear_prompt_and_stop_widget)

        # Create a tree view list to list out all patients in the directory 
        # selected above
        self.open_patient_window_patients_tree = QTreeWidget()
        self.open_patient_window_patients_tree.setObjectName(
            "OpenPatientWindowPatientsTree")
        self.open_patient_window_patients_tree.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.open_patient_window_patients_tree.resize(
            self.open_patient_window_patients_tree.sizeHint().width(),
            self.open_patient_window_patients_tree.sizeHint().height())
        self.open_patient_window_patients_tree.setHeaderHidden(False)
        self.open_patient_window_patients_tree.setHeaderLabels([""])
        self.open_patient_window_patients_tree.itemChanged.connect(
            self.tree_item_clicked)
        self.open_patient_window_instance_vertical_box.addWidget(
            self.open_patient_window_patients_tree)
        self.last_patient = None

        # Create a label to show what would happen if they select the patient
        self.open_patient_directory_result_label = QtWidgets.QLabel()
        self.open_patient_directory_result_label.setObjectName(
            "OpenPatientDirectoryResultLabel")
        self.open_patient_directory_result_label.setAlignment(Qt.AlignLeft)
        self.open_patient_window_instance_vertical_box.addWidget(
            self.open_patient_directory_result_label)

        # Create a horizontal box to hold the Cancel and Open button
        self.open_patient_window_patient_open_actions_horizontal_box = \
            QHBoxLayout()
        self.open_patient_window_patient_open_actions_horizontal_box. \
            setObjectName("OpenPatientWindowPatientOpenActionsHorizontalBox")
        self.open_patient_window_patient_open_actions_horizontal_box. \
            addStretch(1)
        # Add a button to go back/close from the application
        self.open_patient_window_close_button = QPushButton()
        self.open_patient_window_close_button.setObjectName(
            "OpenPatientWindowcloseButton")
        self.open_patient_window_close_button.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.open_patient_window_close_button.resize(
            self.open_patient_window_stop_button.sizeHint().width(),
            self.open_patient_window_stop_button.sizeHint().height())
        self.open_patient_window_close_button.setCursor(
            QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.open_patient_window_close_button.clicked.connect(
            self.close_button_clicked)
        self.open_patient_window_close_button.setProperty(
            "QPushButtonClass", "fail-button")
        self.open_patient_window_patient_open_actions_horizontal_box. \
            addWidget(self.open_patient_window_close_button)

        # Add a button to confirm opening of the patient
        self.open_patient_window_confirm_button = QPushButton()
        self.open_patient_window_confirm_button.setObjectName(
            "OpenPatientWindowConfirmButton")
        self.open_patient_window_confirm_button.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.open_patient_window_confirm_button.resize(
            self.open_patient_window_confirm_button.sizeHint().width(),
            self.open_patient_window_confirm_button.sizeHint().height())

        self.open_patient_window_confirm_button.setCursor(
            QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.open_patient_window_confirm_button.setDisabled(True)
        self.open_patient_window_confirm_button.clicked.connect(
            self.confirm_button_clicked)
        self.open_patient_window_confirm_button.setProperty(
            "QPushButtonClass", "success-button")
        self.open_patient_window_patient_open_actions_horizontal_box. \
            addWidget(
            self.open_patient_window_confirm_button)

        # Create a widget to house all of the actions button for open patient
        #  window
        self.open_patient_window_patient_open_actions_widget = QWidget()
        self.open_patient_window_patient_open_actions_widget.setLayout(
            self.open_patient_window_patient_open_actions_horizontal_box)
        self.open_patient_window_instance_vertical_box.addWidget(
            self.open_patient_window_patient_open_actions_widget)

        # Set the vertical box fourth element, the tree view, to stretch 
        # out as far as possible
        self.open_patient_window_instance_vertical_box.setStretch(3, 4)
        self.open_patient_window_instance_central_widget = QWidget()
        self.open_patient_window_instance_central_widget.setObjectName(
            "OpenPatientWindowInstanceCentralWidget")
        self.open_patient_window_instance_central_widget.setLayout(
            self.open_patient_window_instance_vertical_box)

        # Create threadpool for multithreading
        self.threadpool = QThreadPool()
        # print("Multithreading with maximum %d threads" % self.threadpool.
        # maxThreadCount())
        # Create interrupt event for stopping the directory search
        self.interrupt_flag = threading.Event()

        # Bind all texts into the buttons and labels
        self.retranslate_ui(open_image_fusion_select_instance)
        # Set the central widget, ready for display
        open_image_fusion_select_instance.setCentralWidget(
            self.open_patient_window_instance_central_widget)

        # Set the current stylesheet to the instance and connect it back 
        # to the caller through slot
        _stylesheet = open(resource_path(self.stylesheet_path)).read()
        open_image_fusion_select_instance.setStyleSheet(_stylesheet)

        QtCore.QMetaObject.connectSlotsByName(
            open_image_fusion_select_instance)

    def retranslate_ui(self, open_image_fusion_select_instance):
        """Translates UI"""
        _translate = QtCore.QCoreApplication.translate
        open_image_fusion_select_instance.setWindowTitle(
            _translate("OpenPatientWindowInstance",
                       "OnkoDICOM - Select Patient"))
        self.open_patient_directory_prompt.setText(_translate(
            "OpenPatientWindowInstance",
            "Choose an image to merge with:"))
        self.open_patient_directory_input_box.setPlaceholderText(
            _translate("OpenPatientWindowInstance",
                       "Enter DICOM Files Path (For example, "
                       "C:\path\\to\your\DICOM\Files)"))
        self.open_patient_directory_choose_button.setText(_translate(
            "OpenPatientWindowInstance",
            "Choose"))
        self.open_patient_directory_appear_prompt.setText(_translate(
            "OpenPatientWindowInstance",
            "Please select below the image set you wish to overlay:"))
        self.open_patient_directory_result_label. \
            setText("The selected imageset(s) above will be "
                    "co-registered with the current imageset.")
        self.open_patient_window_stop_button.setText(_translate(
            "OpenPatientWindowInstance", "Stop Search"))
        self.open_patient_window_close_button.setText(_translate(
            "OpenPatientWindowInstance", "Close"))
        self.open_patient_window_confirm_button.setText(_translate(
            "OpenPatientWindowInstance", "Confirm"))

    def update_patient(self):
        self.clear_checked_leaves()
        self.patient_dict_container = PatientDictContainer()
        self.patient = self.patient_dict_container.get("basic_info")
        self.patient_id = self.patient['id']

        dataset = self.patient_dict_container.dataset[0]
        self.patient_current_image_series_uid = \
            dataset.get("SeriesInstanceUID")

    def clear_checked_leaves(self):
        """
        Resets all leaves to their unchecked state
        """
        def recurse(parent_item: QTreeWidgetItem):
            for i in range(parent_item.childCount()):
                child = parent_item.child(i)
                grand_children = child.childCount()
                if grand_children > 0:
                    recurse(child)
                else:
                    if child.checkState(0) == Qt.Checked:
                        child.setCheckState(0, Qt.CheckState.Unchecked)
                        child.setSelected(False)

        recurse(self.open_patient_window_patients_tree.invisibleRootItem())
        self.open_patient_window_patients_tree.collapseAll()

    def close_button_clicked(self):
        """Closes the window."""
        self.close()

    def scan_directory_for_patient(self):
        # Reset tree view header and last patient
        self.open_patient_window_confirm_button.setDisabled(True)
        self.open_patient_window_patients_tree.setHeaderLabels([""])
        self.last_patient = None
        self.filepath = self.open_patient_directory_input_box.text()
        # Proceed if a folder was selected
        if self.filepath != "":
            # Update the QTreeWidget to reflect data being loaded
            # First, clear the widget of any existing data
            self.open_patient_window_patients_tree.clear()

            # Next, update the tree widget
            self.open_patient_window_patients_tree.addTopLevelItem(
                QTreeWidgetItem(["Loading selected directory..."]))

            # The choose button is disabled until the thread finishes executing
            self.open_patient_directory_choose_button.setEnabled(False)

            # Reveals the Stop Search button for the duration of the search
            self.open_patient_window_stop_button.setVisible(True)

            # The interrupt flag is then un-set if a previous search has been
            # stopped.
            self.interrupt_flag.clear()

            # Then, create a new thread that will load the selected folder
            worker = Worker(DICOMDirectorySearch.get_dicom_structure,
                            self.filepath,
                            self.interrupt_flag, progress_callback=True)
            worker.signals.result.connect(self.on_search_complete)
            worker.signals.progress.connect(self.search_progress)

            # Execute the thread
            self.threadpool.start(worker)

    def choose_button_clicked(self):
        """
        Executes when the choose button is clicked.
        Gets filepath from the user and loads all files and subdirectories.
        """
        # Get folder path from pop up dialog box
        self.filepath = QtWidgets.QFileDialog.getExistingDirectory(
            None, 'Select patient folder...', '')
        self.open_patient_directory_input_box.setText(self.filepath)
        self.scan_directory_for_patient()

    def stop_button_clicked(self):
        self.interrupt_flag.set()

    def search_progress(self, progress_update):
        """
        Current progress of the file search.
        """
        self.open_patient_window_patients_tree.clear()
        self.open_patient_window_patients_tree.addTopLevelItem(
            QTreeWidgetItem(["Loading selected directory... "
                             "(%s files searched)" % progress_update]))

    def on_search_complete(self, dicom_structure):
        """
        Executes once the directory search is complete.
        :param dicom_structure: DICOMStructure object constructed by the
        directory search.
        """
        self.open_patient_directory_choose_button.setEnabled(True)
        self.open_patient_window_stop_button.setVisible(False)
        self.open_patient_window_patients_tree.clear()

        # dicom_structure will be None if function was interrupted.
        if dicom_structure is None:
            return

        for patient_item in dicom_structure.get_tree_items_list():
            self.open_patient_window_patients_tree.addTopLevelItem(
                patient_item)
            patient_item.setExpanded(True)  # Display all studies
            # Display all image sets
            for i in range(patient_item.childCount()):
                study = patient_item.child(i)
                study.setExpanded(True)

        if len(dicom_structure.patients) == 0:
            QMessageBox.about(self, "No files found",
                              "Selected directory contains no DICOM files.")

    def tree_item_clicked(self, item, _):
        """
        Executes when a tree item is checked or unchecked.
        If a different patient is checked, uncheck the previous patient.
        Inform user about missing DICOM files.
        """
        # If patient is only selected, but not checked, set it to "focus" to
        # coincide with stylesheet. And if the selected item is an image set,
        # display its child branches.
        if item.checkState(0) == Qt.CheckState.Unchecked:
            self.open_patient_window_patients_tree.setCurrentItem(item)
        else:  # Otherwise don't "focus", then set patient as selected
            self.open_patient_window_patients_tree.setCurrentItem(None)
            item.setSelected(True)

        # Expand or collapse the tree branch if item is an image series
        # Only collapse if the selected image series is expanded but unchecked
        # Otherwise, expand its tree branch to show RT files
        is_expanded = False \
            if (item.isExpanded() is True and
                item.checkState(0) == Qt.CheckState.Unchecked) else True
        self.display_a_tree_branch(item, is_expanded)

        selected_patient = item
        # If the item is not top-level, bubble up to see which top-level item
        # this item belongs to
        if self.open_patient_window_patients_tree.invisibleRootItem(). \
                indexOfChild(item) == -1:
            while self.open_patient_window_patients_tree.invisibleRootItem(). \
                    indexOfChild(selected_patient) == -1:
                selected_patient = selected_patient.parent()

        # Uncheck previous patient if a different patient is selected
        if item.checkState(0) == Qt.CheckState.Checked and self.last_patient \
                != selected_patient:
            if self.last_patient is not None:
                last_patient_checked_items = self.get_checked_nodes(
                    self.last_patient)
                for checked_item in last_patient_checked_items:
                    checked_item.setCheckState(0, Qt.Unchecked)
            self.last_patient = selected_patient

        # Check selected items and display warning messages
        self.check_selected_items(selected_patient)

    def display_a_tree_branch(self, node, is_expanded):
        # TO DO:
        # Could Team 23 please update the defintion of this docstring as
        # well as same function presented in OpenPatientWindow.
        """
        Displays a tree branch
        Parameters:
            node : root node the tree
            is_expanded (boolean): flag for checking if a particular
            node/leaf is expanded.
        """
        node.setExpanded(is_expanded)
        if node.childCount() > 0:
            for i in range(node.childCount()):
                self.display_a_tree_branch(node.child(i), is_expanded)
        else:
            return

    def check_selected_items(self, selected_patient):
        """
        Check and display warning messages based on the existence and quantity
        of image series, RTSTRUCT, RTPLAN, RTDOSE and SR files

        Parameters:
            selected_patient (DICOMStructure): DICOM Object of patient
        """
        # Get the types of all selected leaves & Get the names of all selected
        # studies
        checked_nodes = self.get_checked_nodes(
            self.open_patient_window_patients_tree.invisibleRootItem())
        selected_series_types = [checked_node.dicom_object.get_series_type()
                                 for checked_node in checked_nodes]
        selected_series_id = [checked_node.dicom_object.series_uid
                              for checked_node in checked_nodes]

        # Total number of selected image series
        total_selected_image_series = selected_series_types.count('CT') + \
                                      selected_series_types.count('MR') + \
                                      selected_series_types.count('PT')

        # Check the existence of IMAGE, RTSTRUCT, RTPLAN and RTDOSE files
        proceed = True

        if total_selected_image_series < 1:
            header = "Cannot proceed without an image."
            proceed = False
        elif total_selected_image_series > 1:
            header = "Cannot proceed with more than 1 selected image."
            proceed = False
        elif selected_patient.dicom_object.patient_id.strip() != \
                self.patient_id:
            header = "Cannot proceed with different patient."
            proceed = False
        elif self.patient_current_image_series_uid in selected_series_id:
            header = "Cannot fuse with the same series."
            proceed = False
        elif not self.check_selected_items_referencing(checked_nodes):
            # Check that selected items properly reference each other
            header = "Selected series do not reference each other."
            proceed = False
        elif 'RTSTRUCT' not in selected_series_types and \
            self.check_existing_rtss(checked_nodes):
            header = "The associated RTSTRUCT must be selected."
            proceed = False
        elif 'RTDOSE' in selected_series_types:
            header = "Cannot fuse with a RTDOSE file."
            proceed = False
        else:
            header = ""
        self.open_patient_window_confirm_button.setDisabled(not proceed)

        # Set the tree header
        self.open_patient_window_patients_tree.setHeaderLabel(header)

    def check_selected_items_referencing(self, items):
        """
        Check if selected tree items properly reference each other.
        :param items: List of selected DICOMWidgetItems.
        :return: True if the selected items belong to the same tree branch.
        """
        # Dictionary of series of different file types
        series = {
            "IMAGE": None,
            "RTSTRUCT": None,
            "RTPLAN": None,
            "RTDOSE": None,
            "SR": None
        }

        for item in items:
            series_type = item.dicom_object.get_series_type()
            if series_type in series:
                series[series_type] = item
            else:
                series["IMAGE"] = item

        # Check if the RTSTRUCT, RTPLAN, and RTDOSE are a child item of the
        # image series
        if series["IMAGE"]:
            if series["RTSTRUCT"] and series["RTSTRUCT"].parent() != \
                    series["IMAGE"]:
                return False

            if series["RTPLAN"] and \
                    series["RTPLAN"].parent().parent() != series["IMAGE"]:
                return False

            if series["SR"] and series["SR"].parent() != series["IMAGE"]:
                return False

        return True

    def check_existing_rtss(self, items):
        """
        Check for existing rtss
        :return: bool, whether there is a rtss associated with the selected
        image series
        """
        image_series = ['CT', 'MR', 'PT']
        for item in items:
            if item.dicom_object.get_series_type() in image_series:
                for i in range(item.childCount()):
                    if item.child(i).dicom_object:
                        return True
                return False

    def get_checked_nodes(self, root):
        """
        :param root: QTreeWidgetItem as a root.
        :return: A list of all QTreeWidgetItems in the QTreeWidget that are
        checked under the root.
        """
        checked_items = []

        def recurse(parent_item: QTreeWidgetItem):
            for i in range(parent_item.childCount()):
                child = parent_item.child(i)
                if int(child.flags()) & int(Qt.ItemIsUserCheckable) and \
                        child.checkState(0) == Qt.Checked:
                    checked_items.append(child)
                grand_children = child.childCount()
                if grand_children > 0:
                    recurse(child)

        recurse(root)
        return checked_items

    def confirm_button_clicked(self):
        """
        Begins loading of the selected files.
        """
        selected_files = []
        for item in self.get_checked_nodes(
                self.open_patient_window_patients_tree.invisibleRootItem()):
            selected_files += item.dicom_object.get_files()

        self.progress_window = ImageFusionProgressWindow(self)
        self.progress_window.signal_loaded.connect(self.on_loaded)
        self.progress_window.signal_error.connect(self.on_loading_error)
        self.progress_window.start_loading(selected_files)

    def on_loaded(self, results):
        """
        Executes when the progress bar finishes loaded the selected files.
        """
        if results[0] is True:  # Will be NoneType if loading was interrupted.
            self.image_fusion_info_initialized.emit(results[1])

    def on_loading_error(self, exception):
        """
        Error handling for progress window.
        """
        if type(exception[1]) == ImageLoading.NotRTSetError:
            QMessageBox.about(self.progress_window,
                              "Unable to open selection",
                              "Selected files cannot be opened as they are not"
                              " a DICOM-RT set.")
            self.progress_window.close()
        elif type(exception[1]) == ImageLoading.NotAllowedClassError:
            QMessageBox.about(self.progress_window,
                              "Unable to open selection",
                              "Selected files cannot be opened as they contain"
                              " unsupported DICOM classes.")
            self.progress_window.close()
class UIFirstTimeWelcomeWindow(object):
    configured = QtCore.Signal(str)

    # the ui constructor function
    def setup_ui(self, first_time_welcome_window_instance):
        self.filepath = ""
        if platform.system() == 'Darwin':
            self.stylesheet_path = "res/stylesheet.qss"
        else:
            self.stylesheet_path = "res/stylesheet-win-linux.qss"

        window_icon = QtGui.QIcon()
        window_icon.addPixmap(
            QtGui.QPixmap(resource_path("res/images/icon.ico")),
            QtGui.QIcon.Normal, QtGui.QIcon.Off)  # adding icon
        first_time_welcome_window_instance.setObjectName(
            "FirstTimeWelcomeWindowInstance")
        first_time_welcome_window_instance.setWindowIcon(window_icon)
        first_time_welcome_window_instance.setFixedSize(840, 530)

        # Create a vertical layout to manage layout in a vertical manner
        self.window_vertical_layout_box = QVBoxLayout()
        self.window_vertical_layout_box.setObjectName(
            "FirstTimeWelcomeWindowInstanceVerticalLayoutBox")

        # Create a horizontal box to hold the Onko logo & welcome message
        self.first_time_welcome_logo_message_horizontal_box = QHBoxLayout()
        self.first_time_welcome_logo_message_horizontal_box.setObjectName(
            "FirstTimeWelcomeLogoMessageBox")

        # Set up the Logo Holder
        self.logo_holder = QtWidgets.QHBoxLayout()
        self.first_time_welcome_logo = QtWidgets.QLabel()
        self.first_time_welcome_logo.setPixmap(
            QtGui.QPixmap(resource_path("res/images/image.png")))
        self.first_time_welcome_logo.setScaledContents(True)
        self.first_time_welcome_logo.setObjectName(
            "FirstTimeWelcomeWindowLogo")
        self.first_time_welcome_logo.setFixedSize(240, 130)
        self.logo_holder.addWidget(self.first_time_welcome_logo)
        self.first_time_welcome_logo_message_horizontal_box.addLayout(
            self.logo_holder)

        # Create a vertical box to hold the welcome message
        self.first_time_welcome_message_vertical_box = QVBoxLayout()
        self.first_time_welcome_message_vertical_box.setObjectName(
            "FirstTimeWelcomeWindowWelcomeMessage")

        # Set up the Label
        self.first_time_welcome_message_label = QtWidgets.QLabel()
        self.first_time_welcome_message_label.setObjectName(
            "FirstTimeWelcomeWindowLabel")
        self.first_time_welcome_message_label.setAlignment(Qt.AlignLeft)
        self.first_time_welcome_message_vertical_box.addWidget(
            self.first_time_welcome_message_label)

        # Set up the Slogan
        self.first_time_welcome_message_slogan = QtWidgets.QLabel()
        self.first_time_welcome_message_slogan.setObjectName(
            "FirstTimeWelcomeWindowSlogan")
        self.first_time_welcome_message_slogan.setAlignment(Qt.AlignLeft)
        self.first_time_welcome_message_slogan.setWordWrap(True)
        self.first_time_welcome_message_vertical_box.addWidget(
            self.first_time_welcome_message_slogan)

        self.first_time_welcome_message_slogan_widget = QWidget()
        self.first_time_welcome_message_slogan_widget.setLayout(
            self.first_time_welcome_message_vertical_box)
        self.first_time_welcome_logo_message_horizontal_box.addWidget(
            self.first_time_welcome_message_slogan_widget)

        self.first_time_welcome_logo_message_widget = QWidget()
        self.first_time_welcome_logo_message_widget.setLayout(
            self.first_time_welcome_logo_message_horizontal_box)
        self.window_vertical_layout_box.addWidget(
            self.first_time_welcome_logo_message_widget)

        # Create a label to prompt the user to enter the path to the default directory
        self.first_time_welcome_default_dir_prompt = QtWidgets.QLabel()
        self.first_time_welcome_default_dir_prompt.setObjectName(
            "FirstTimeWelcomeWindowPrompt")
        self.first_time_welcome_default_dir_prompt.setAlignment(Qt.AlignLeft)
        self.window_vertical_layout_box.addWidget(
            self.first_time_welcome_default_dir_prompt)

        # Create a horizontal box to hold the input box for the directory and the choose button
        self.first_time_welcome_input_horizontal_box = QHBoxLayout()
        self.first_time_welcome_input_horizontal_box.setObjectName(
            "FirstTimeWelcomeWindowInputHorizontalBox")

        # Create a textbox to contain the path to the default directory
        self.first_time_welcome_input_box = UIFirstTimeUserDragAndDropEvent(
            self)

        self.first_time_welcome_input_box.setObjectName(
            "FirstTimeWelcomeWindowInputBox")
        self.first_time_welcome_input_box.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.first_time_welcome_input_horizontal_box.addWidget(
            self.first_time_welcome_input_box)

        # Create a choose button to open the file dialog
        self.first_time_welcome_choose_button = QPushButton()
        self.first_time_welcome_choose_button.setObjectName(
            "FirstTimeWelcomeWindowChooseButton")
        self.first_time_welcome_choose_button.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.first_time_welcome_choose_button.resize(
            self.first_time_welcome_choose_button.sizeHint().width(),
            self.first_time_welcome_input_box.height())
        self.first_time_welcome_choose_button.setCursor(
            QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.first_time_welcome_input_horizontal_box.addWidget(
            self.first_time_welcome_choose_button)
        self.first_time_welcome_choose_button.clicked.connect(
            self.choose_button_clicked)

        # Create a widget to hold the input field
        self.first_time_welcome_input_widget = QWidget()
        self.first_time_welcome_input_horizontal_box.setStretch(0, 4)
        self.first_time_welcome_input_widget.setLayout(
            self.first_time_welcome_input_horizontal_box)
        self.window_vertical_layout_box.addWidget(
            self.first_time_welcome_input_widget)
        self.window_vertical_layout_box.addStretch(1)

        # Create widgets for the clinical data CSV file path
        self.clinical_data_csv_dir_label = QtWidgets.QLabel()
        self.clinical_data_csv_dir_label.setObjectName("ClinicalDataCSVPrompt")
        self.clinical_data_csv_dir_label.setAlignment(Qt.AlignLeft)
        self.window_vertical_layout_box.addWidget(
            self.clinical_data_csv_dir_label)

        # Create a horizontal box to hold the input box for the
        # directory and the choose button
        self.clinical_data_csv_horizontal_box = QHBoxLayout()
        self.clinical_data_csv_horizontal_box.setObjectName(
            "ClinicalDataCSVHorizontalBox")

        # Create a textbox to contain the path to the default directory
        self.clinical_data_csv_input_box = \
            UIFirstTimeUserDragAndDropEvent(self)

        self.clinical_data_csv_input_box.setObjectName(
            "ClinicalDataCSVInputBox")
        self.clinical_data_csv_input_box.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.clinical_data_csv_horizontal_box.addWidget(
            self.clinical_data_csv_input_box)

        # Create a choose button to open the file dialog
        self.clinical_data_csv_choose_button = QPushButton()
        self.clinical_data_csv_choose_button.setObjectName(
            "ClinicalDataCSVChooseButton")
        self.clinical_data_csv_choose_button.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.clinical_data_csv_choose_button.resize(
            self.clinical_data_csv_choose_button.sizeHint().width(),
            self.clinical_data_csv_input_box.height())
        self.clinical_data_csv_choose_button.setCursor(
            QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.clinical_data_csv_horizontal_box.addWidget(
            self.clinical_data_csv_choose_button)
        self.clinical_data_csv_choose_button.clicked.connect(
            self.change_clinical_data_csv_button_clicked)

        # Create a widget to hold the input field
        self.clinical_data_input_widget = QWidget()
        self.clinical_data_csv_horizontal_box.setStretch(0, 4)
        self.clinical_data_input_widget.setLayout(
            self.clinical_data_csv_horizontal_box)
        self.window_vertical_layout_box.addWidget(
            self.clinical_data_input_widget)
        self.window_vertical_layout_box.addStretch(1)

        # Create a horizontal box to hold the Skip and Confirm button
        self.first_time_window_configure_actions_horizontal_box = QHBoxLayout()
        self.first_time_window_configure_actions_horizontal_box.setObjectName(
            "FirstTimeWelcomeWindowConfigureActionsHorizontalBox")
        self.first_time_window_configure_actions_horizontal_box.addStretch(1)

        # Add a button to skip the configuration setting
        self.skip_button = QPushButton()
        self.skip_button.setObjectName("SkipButton")
        self.skip_button.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.skip_button.resize(self.skip_button.sizeHint().width(),
                                self.skip_button.sizeHint().height())
        self.skip_button.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.skip_button.setProperty("QPushButtonClass", "fail-button")
        self.first_time_window_configure_actions_horizontal_box.addWidget(
            self.skip_button)

        # Add a button to save the default directory
        self.save_dir_button = QPushButton()
        self.save_dir_button.setObjectName("SaveDirButton")
        self.save_dir_button.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding,
                        QSizePolicy.MinimumExpanding))
        self.save_dir_button.resize(self.save_dir_button.sizeHint().width(),
                                    self.save_dir_button.sizeHint().height())
        self.save_dir_button.setCursor(
            QtGui.QCursor(QtCore.Qt.PointingHandCursor))
        self.save_dir_button.clicked.connect(self.save_options)
        self.save_dir_button.setProperty("QPushButtonClass", "success-button")
        self.first_time_window_configure_actions_horizontal_box.addWidget(
            self.save_dir_button)

        # Create a widget to house all of the actions button for first-time window
        self.first_time_window_configure_actions_widget = QWidget()
        self.first_time_window_configure_actions_widget.setLayout(
            self.first_time_window_configure_actions_horizontal_box)
        self.window_vertical_layout_box.addWidget(
            self.first_time_window_configure_actions_widget)

        self.first_time_window_instance_central_widget = QWidget()
        self.first_time_window_instance_central_widget.setLayout(
            self.window_vertical_layout_box)
        first_time_welcome_window_instance.setCentralWidget(
            self.first_time_window_instance_central_widget)

        # Set the current stylesheet to the instance and connect it back to the caller through slot
        _stylesheet = open(resource_path(self.stylesheet_path)).read()
        first_time_welcome_window_instance.setStyleSheet(_stylesheet)
        self.retranslate_ui(first_time_welcome_window_instance)
        QtCore.QMetaObject.connectSlotsByName(
            first_time_welcome_window_instance)

    # this function inserts all the text in the first time page
    def retranslate_ui(self, first_time_welcome_window_instance):
        _translate = QtCore.QCoreApplication.translate
        first_time_welcome_window_instance.setWindowTitle(
            _translate("FirstTimeWelcomeWindowInstance",
                       "OnkoDICOM - First-time User Setting"))
        self.first_time_welcome_message_label.setText(
            _translate("FirstTimeWelcomeWindowInstance",
                       "Welcome to OnkoDICOM!"))
        self.first_time_welcome_message_slogan.setText(
            _translate(
                "FirstTimeWelcomeWindowInstance",
                "OnkoDICOM - the solution for producing data for analysis from your oncology plans and scans."
            ))
        self.first_time_welcome_default_dir_prompt.setText(
            _translate(
                "FirstTimeWelcomeWindowInstance",
                "Choose the path of the default directory containing all DICOM files:"
            ))
        self.first_time_welcome_input_box.setPlaceholderText(
            _translate(
                "FirstTimeWelcomeWindowInstance",
                "Enter DICOM Files Path (For example, C:\path\\to\your\DICOM\Files)"
            ))
        self.first_time_welcome_choose_button.setText(
            _translate("FirstTimeWelcomeWindowInstance", "Choose"))

        # Clinical data CSV widgets
        self.clinical_data_csv_dir_label.setText(
            _translate(
                "FirstTimeWelcomeWindowInstance",
                "Choose the CSV file containing patient clinical data:"))
        self.clinical_data_csv_input_box.setPlaceholderText(
            _translate("FirstTimeWelcomeWindowInstance",
                       "Enter CSV File Path (for example, C:\CSV\\file.csv)"))
        self.clinical_data_csv_choose_button.setText(
            _translate("FirstTimeWelcomeWindowInstance", "Choose"))

        self.save_dir_button.setText(
            _translate("FirstTimeWelcomeWindowInstance", "Confirm"))
        self.skip_button.setText(
            _translate("FirstTimeWelcomeWindowInstance", "Skip"))

    def save_options(self):
        """
        Saves options selected in the first time welcome window.
        """
        self.filepath = self.first_time_welcome_input_box.text()
        self.csv_path = self.clinical_data_csv_input_box.text()
        if self.filepath == "" and self.csv_path == "":
            QMessageBox.about(self, "Unable to proceed",
                              "No directories selected.")
        elif not os.path.exists(self.filepath) or not \
                os.path.exists(self.csv_path):
            QMessageBox.about(self, "Unable to proceed",
                              "Directories do not exist")
        else:
            config = Configuration()
            try:
                config.update_default_directory(self.filepath)

                # Update CSV path if it exists
                if self.csv_path != "" and os.path.exists(self.csv_path):
                    config.update_clinical_data_csv_dir(self.csv_path)
            except SqlError:
                config.set_up_config_db()
                QMessageBox.critical(
                    self, "Config file error",
                    "Failed to access configuration file.\nPlease try again.")
            else:
                self.configured.emit(self.filepath)

    def choose_button_clicked(self):
        """
        Executes when the choose button is clicked.
        Gets filepath from the user and loads all files and subdirectories.
        """
        # Get folder path from pop up dialog box
        self.filepath = QtWidgets.QFileDialog.getExistingDirectory(
            None, 'Select default directory...', '')
        self.first_time_welcome_input_box.setText(self.filepath)

    def change_clinical_data_csv_button_clicked(self):
        """
        Executes when the choose button is clicked.
        Gets filepath from the user.
        """
        # Get folder path from pop up dialog box
        self.csv_path = QtWidgets.QFileDialog.getOpenFileName(
            None, "Open Clinical Data File", "", "CSV data files (*.csv)")[0]
        if len(self.csv_path) > 0:
            self.clinical_data_csv_input_box.setText(self.csv_path)
Beispiel #10
0
class MainWindow(QMainWindow):
    def __init__(self, stages: list[Stage], *args, **kwargs):
        QMainWindow.__init__(self, *args, **kwargs)
        if not self.objectName():
            self.setObjectName("MainWindow")
        self.resize(800, 600)
        size_policy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        size_policy.setHorizontalStretch(0)
        size_policy.setVerticalStretch(0)
        size_policy.setHeightForWidth(self.sizePolicy().hasHeightForWidth())
        self.setSizePolicy(size_policy)
        self.setWindowTitle("Interfan")

        self.central_widget = QWidget(self)
        self.central_widget.setObjectName("central_widget")

        self.main_horizontal_layout = QHBoxLayout(self.central_widget)
        self.main_horizontal_layout.setObjectName("main_horizontal_layout")

        self.left_grid_layout = QGridLayout()
        self.left_grid_layout.setObjectName("left_grid_layout")

        self.slice_slider = QSlider(self.central_widget)
        self.slice_slider.setObjectName("slice_slider")
        self.slice_slider.setEnabled(False)
        self.slice_slider.setOrientation(Qt.Horizontal)

        self.left_grid_layout.addWidget(self.slice_slider, 1, 0, 1, 1)

        self.slice_label = QLabel(self.central_widget)
        self.slice_label.setObjectName("slice_label")
        self.slice_label.setGeometry(QRect(0, 10, 58, 18))
        self.slice_label.setText("0")
        self.left_grid_layout.addWidget(self.slice_label, 1, 1, 1, 1)

        self.main_image_scene = QGraphicsScene()
        self.main_image_view = QGraphicsView(self.main_image_scene)
        self.main_image_view.setObjectName("main_image_view")
        self.left_grid_layout.addWidget(self.main_image_view, 0, 0, 1, 1)

        self.slice_image_scene = QGraphicsScene()
        self.slice_image_view = QGraphicsView(self.slice_image_scene)
        self.slice_image_view.setObjectName("slice_image_view")
        self.left_grid_layout.addWidget(self.slice_image_view, 0, 1, 1, 1)

        self.left_grid_layout.setRowStretch(0, 12)
        self.left_grid_layout.setRowStretch(1, 1)
        self.left_grid_layout.setColumnStretch(0, 6)
        self.left_grid_layout.setColumnStretch(1, 1)

        self.main_horizontal_layout.addLayout(self.left_grid_layout)

        self.right_vertical_layout = QVBoxLayout()
        self.right_vertical_layout.setObjectName("right_vertical_layout")

        self.settings_widget = SettingWidget(self.central_widget)
        self.right_vertical_layout.addWidget(self.settings_widget.group_box)

        self.proceed_button = QPushButton(self.central_widget)
        self.proceed_button.setObjectName("proceed_button")
        self.proceed_button.setText("Выполнить")
        self.proceed_button.setEnabled(False)
        self.right_vertical_layout.addWidget(self.proceed_button)

        self.right_down_layout = QHBoxLayout()
        self.right_down_layout.setObjectName("right_down_layout")
        self.stages_layout = QVBoxLayout()
        self.stages_layout.setObjectName("stages_layout")

        self.stages_label = QLabel(self.central_widget)
        self.stages_label.setObjectName("stages_label")
        self.stages_label.setText("Этапы")
        self.stages_layout.addWidget(self.stages_label, 1)

        self.stages_radio_buttons = []
        for s in stages:
            rb = QRadioButton(self.central_widget)
            rb.setObjectName("stages_radio_button")
            rb.setEnabled(False)
            rb.setText(s.name)
            self.stages_layout.addWidget(rb, 1)
            self.stages_radio_buttons.append(rb)

        self.stages_radio_buttons[0].setEnabled(True)
        self.stages_radio_buttons[0].setChecked(True)
        self.set_stage(stages[0])

        self.right_down_layout.addLayout(self.stages_layout)

        self.history_layout = QVBoxLayout()
        self.history_layout.setObjectName("history_layout")
        self.history_header_layout = QHBoxLayout()
        self.history_header_layout.setObjectName("history_header_layout")

        self.history_label = QLabel(self.central_widget)
        self.history_label.setObjectName("history_label")
        self.history_label.setText("История операций")
        self.history_header_layout.addWidget(self.history_label)

        self.history_minus_button = QToolButton(self.central_widget)
        self.history_minus_button.setObjectName("history_minus_button")
        self.history_minus_button.setEnabled(False)
        self.history_minus_button.setText("-")
        self.history_header_layout.addWidget(self.history_minus_button)

        self.history_header_layout.setStretch(0, 8)
        self.history_header_layout.setStretch(1, 1)

        self.history_layout.addLayout(self.history_header_layout)

        self.history_list_view = QListView(self.central_widget)
        self.history_list_view.setObjectName("history_list_view")
        self.history_layout.addWidget(self.history_list_view)

        self.history_script_button = QPushButton(self.central_widget)
        self.history_script_button.setObjectName("history_script_button")
        self.history_script_button.setText("Просмотреть как скрипт")
        self.history_layout.addWidget(self.history_script_button)

        self.right_down_layout.addLayout(self.history_layout)

        self.right_down_layout.setStretch(0, 1)
        self.right_down_layout.setStretch(1, 1)

        self.right_vertical_layout.addLayout(self.right_down_layout)
        self.right_vertical_layout.setStretch(0, 1)
        self.right_vertical_layout.setStretch(1, 0)
        self.right_vertical_layout.setStretch(2, 1)

        self.main_horizontal_layout.addLayout(self.right_vertical_layout)
        self.main_horizontal_layout.setStretch(0, 1)
        self.main_horizontal_layout.setStretch(1, 1)

        self.setCentralWidget(self.central_widget)
        self.menu_bar = QMenuBar(self)
        self.menu_bar.setObjectName("menu_bar")
        self.menu_bar.setGeometry(QRect(0, 0, 800, 30))
        self.menu = QMenu(self.menu_bar)
        self.menu.setObjectName("men")
        self.menu.setTitle("Меню")
        self.setMenuBar(self.menu_bar)

        self.open_file = QAction(self)
        self.open_file.setObjectName("open_file")
        self.open_file.setText("Открыть файл")
        self.menu.addAction(self.open_file)

        self.status_bar = QStatusBar(self)
        self.status_bar.setObjectName("status_bar")
        self.setStatusBar(self.status_bar)

        self.menu_bar.addAction(self.menu.menuAction())

        QMetaObject.connectSlotsByName(self)

    def set_stage(self, stage: Stage):
        self.settings_widget.change_settings(stage.settings)