ui.dl_selection_page

  1from PyQt6.QtGui import QIcon, QFont
  2from PyQt6.QtWidgets import (
  3    QWidget, QVBoxLayout, QLabel, QPushButton, QGridLayout, QHBoxLayout,
  4    QMessageBox, QGroupBox, QListWidget, QDialog, QLineEdit, QDialogButtonBox, QListWidgetItem
  5)
  6from PyQt6.QtCore import Qt, QCoreApplication
  7import os
  8
  9from components.file_selector_widget import FileSelectorWidget
 10from ui.dl_execution_page import DlExecutionPage
 11from page import Page
 12from logger import get_logger
 13
 14log = get_logger()
 15
 16
 17class DlNiftiSelectionPage(Page):
 18    """
 19    GUI page that allows the user to select NIfTI files for Deep Learning-based segmentation.
 20
 21    This page is part of a multi-step workflow:
 22    - Displays a title and a FileSelectorWidget to pick one or more NIfTI files.
 23    - Checks if a segmentation already exists for a given subject.
 24    - Saves selections in a shared context and navigates to the next page (DlExecutionPage).
 25    """
 26
 27    def __init__(self, context=None, previous_page=None):
 28        """
 29        Initialize the patient selection page.
 30
 31        :param context: Shared application context dictionary (used for data persistence between pages)
 32        :param previous_page: Reference to the previous Page object (for navigation)
 33        """
 34        super().__init__()
 35        self.context = context
 36        self.previous_page = previous_page
 37        self.next_page = None  # Will be created when advancing
 38
 39        self._setup_ui()
 40        self._translate_ui()
 41
 42        # Re-translate the UI dynamically if the language changes in the context
 43        if context and "language_changed" in context:
 44            context["language_changed"].connect(self._translate_ui)
 45
 46    def _setup_ui(self):
 47        """Create and organize all UI elements for this page."""
 48        self.layout = QVBoxLayout(self)
 49        self.setLayout(self.layout)
 50
 51        # Title label
 52        self.title = QLabel("Select NIfTI files for Deep Learning Segmentation")
 53        self.title.setFont(QFont("Arial", 18, QFont.Weight.Bold))
 54        self.title.setAlignment(Qt.AlignmentFlag.AlignCenter)
 55        self.layout.addWidget(self.title)
 56
 57        # Widget for selecting NIfTI files
 58        # - `has_existing_function` allows pre-checking if a segmentation already exists
 59        self.file_selector_widget = FileSelectorWidget(
 60            parent=self,
 61            context=self.context,
 62            has_existing_function=self.has_existing_segmentation,
 63            label="seg",
 64            allow_multiple=True
 65        )
 66        self.layout.addWidget(self.file_selector_widget)
 67
 68        # Pushes everything upward visually
 69        self.layout.addStretch()
 70
 71        # Label for displaying temporary status or messages
 72        self.status_label = QLabel("")
 73        self.status_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
 74        self.layout.addWidget(self.status_label)
 75
 76    def has_existing_segmentation(self, nifti_file_path, workspace_path):
 77        """
 78        Check if a deep learning segmentation already exists for the patient corresponding to this NIfTI file.
 79
 80        :param nifti_file_path: Full path to the selected NIfTI file.
 81        :param workspace_path: Root path of the working directory.
 82        :return: True if a segmentation file is already present, otherwise False.
 83        """
 84        # Extract patient ID (subject ID) from the NIfTI file path
 85        path_parts = nifti_file_path.replace(workspace_path, '').strip(os.sep).split(os.sep)
 86
 87        # Look for a directory segment starting with 'sub-' (BIDS convention)
 88        subject_id = None
 89        for part in path_parts:
 90            if part.startswith('sub-'):
 91                subject_id = part
 92                break
 93
 94        # If no subject identifier found, no segmentation can be associated
 95        if not subject_id:
 96            return False
 97
 98        # Expected directory where segmentations are stored
 99        seg_dir = os.path.join(workspace_path, 'derivatives', 'deep_learning_seg', subject_id, 'anat')
100
101        # If the segmentation directory does not exist, return False
102        if not os.path.exists(seg_dir):
103            return False
104
105        # Check for any segmentation file in the directory
106        for file in os.listdir(seg_dir):
107            if file.endswith('_seg.nii.gz') or file.endswith('_seg.nii'):
108                return True
109
110        return False
111
112    def back(self):
113        """
114        Navigate back to the previous page in the workflow.
115
116        :return: The previous Page instance, or None if there is none.
117        """
118        if self.previous_page:
119            self.previous_page.on_enter()
120            return self.previous_page
121        return None
122
123    def next(self, context):
124        """
125        Save the selected files in the context and move to the next page (DlExecutionPage).
126
127        :param context: The shared application context dictionary.
128        :return: The next Page instance.
129        """
130        # Store selected files in the context
131        if self.context is not None:
132            self.context["selected_segmentation_files"] = self.file_selector_widget.get_selected_files()
133
134        # Instantiate the next page only once
135        if not self.next_page:
136            self.next_page = DlExecutionPage(self.context, self)
137            if "history" in self.context:
138                self.context["history"].append(self.next_page)
139
140        # Prepare the next page before displaying
141        self.next_page.on_enter()
142        return self.next_page
143
144    def on_enter(self):
145        """Called when the page is shown — resets transient UI elements."""
146        self.status_label.setText("")
147
148    def is_ready_to_advance(self):
149        """
150        Check if the user can proceed to the next page.
151
152        :return: True if one or more files are selected.
153        """
154        return self.file_selector_widget.get_selected_files()
155
156    def is_ready_to_go_back(self):
157        """
158        Check if the user can navigate backward.
159
160        :return: Always True for this page.
161        """
162        return True
163
164    def reset_page(self):
165        """
166        Reset the page to its initial state, clearing all selections and messages.
167        """
168        self.file_selector_widget._selected_files = []
169
170        self.status_label.setText("")
171
172        # Clear any saved data in the context
173        if self.context:
174            self.context["selected_segmentation_files"] = []
175
176    def _translate_ui(self):
177        """Apply translations to all text elements in the UI."""
178        self.title.setText(QCoreApplication.translate(
179            "DlSelectionPage",
180            "Select NIfTI files for Deep Learning Segmentation"
181        ))
log = <Logger GliAAns-UI (WARNING)>
class DlNiftiSelectionPage(page.Page):
 18class DlNiftiSelectionPage(Page):
 19    """
 20    GUI page that allows the user to select NIfTI files for Deep Learning-based segmentation.
 21
 22    This page is part of a multi-step workflow:
 23    - Displays a title and a FileSelectorWidget to pick one or more NIfTI files.
 24    - Checks if a segmentation already exists for a given subject.
 25    - Saves selections in a shared context and navigates to the next page (DlExecutionPage).
 26    """
 27
 28    def __init__(self, context=None, previous_page=None):
 29        """
 30        Initialize the patient selection page.
 31
 32        :param context: Shared application context dictionary (used for data persistence between pages)
 33        :param previous_page: Reference to the previous Page object (for navigation)
 34        """
 35        super().__init__()
 36        self.context = context
 37        self.previous_page = previous_page
 38        self.next_page = None  # Will be created when advancing
 39
 40        self._setup_ui()
 41        self._translate_ui()
 42
 43        # Re-translate the UI dynamically if the language changes in the context
 44        if context and "language_changed" in context:
 45            context["language_changed"].connect(self._translate_ui)
 46
 47    def _setup_ui(self):
 48        """Create and organize all UI elements for this page."""
 49        self.layout = QVBoxLayout(self)
 50        self.setLayout(self.layout)
 51
 52        # Title label
 53        self.title = QLabel("Select NIfTI files for Deep Learning Segmentation")
 54        self.title.setFont(QFont("Arial", 18, QFont.Weight.Bold))
 55        self.title.setAlignment(Qt.AlignmentFlag.AlignCenter)
 56        self.layout.addWidget(self.title)
 57
 58        # Widget for selecting NIfTI files
 59        # - `has_existing_function` allows pre-checking if a segmentation already exists
 60        self.file_selector_widget = FileSelectorWidget(
 61            parent=self,
 62            context=self.context,
 63            has_existing_function=self.has_existing_segmentation,
 64            label="seg",
 65            allow_multiple=True
 66        )
 67        self.layout.addWidget(self.file_selector_widget)
 68
 69        # Pushes everything upward visually
 70        self.layout.addStretch()
 71
 72        # Label for displaying temporary status or messages
 73        self.status_label = QLabel("")
 74        self.status_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
 75        self.layout.addWidget(self.status_label)
 76
 77    def has_existing_segmentation(self, nifti_file_path, workspace_path):
 78        """
 79        Check if a deep learning segmentation already exists for the patient corresponding to this NIfTI file.
 80
 81        :param nifti_file_path: Full path to the selected NIfTI file.
 82        :param workspace_path: Root path of the working directory.
 83        :return: True if a segmentation file is already present, otherwise False.
 84        """
 85        # Extract patient ID (subject ID) from the NIfTI file path
 86        path_parts = nifti_file_path.replace(workspace_path, '').strip(os.sep).split(os.sep)
 87
 88        # Look for a directory segment starting with 'sub-' (BIDS convention)
 89        subject_id = None
 90        for part in path_parts:
 91            if part.startswith('sub-'):
 92                subject_id = part
 93                break
 94
 95        # If no subject identifier found, no segmentation can be associated
 96        if not subject_id:
 97            return False
 98
 99        # Expected directory where segmentations are stored
100        seg_dir = os.path.join(workspace_path, 'derivatives', 'deep_learning_seg', subject_id, 'anat')
101
102        # If the segmentation directory does not exist, return False
103        if not os.path.exists(seg_dir):
104            return False
105
106        # Check for any segmentation file in the directory
107        for file in os.listdir(seg_dir):
108            if file.endswith('_seg.nii.gz') or file.endswith('_seg.nii'):
109                return True
110
111        return False
112
113    def back(self):
114        """
115        Navigate back to the previous page in the workflow.
116
117        :return: The previous Page instance, or None if there is none.
118        """
119        if self.previous_page:
120            self.previous_page.on_enter()
121            return self.previous_page
122        return None
123
124    def next(self, context):
125        """
126        Save the selected files in the context and move to the next page (DlExecutionPage).
127
128        :param context: The shared application context dictionary.
129        :return: The next Page instance.
130        """
131        # Store selected files in the context
132        if self.context is not None:
133            self.context["selected_segmentation_files"] = self.file_selector_widget.get_selected_files()
134
135        # Instantiate the next page only once
136        if not self.next_page:
137            self.next_page = DlExecutionPage(self.context, self)
138            if "history" in self.context:
139                self.context["history"].append(self.next_page)
140
141        # Prepare the next page before displaying
142        self.next_page.on_enter()
143        return self.next_page
144
145    def on_enter(self):
146        """Called when the page is shown — resets transient UI elements."""
147        self.status_label.setText("")
148
149    def is_ready_to_advance(self):
150        """
151        Check if the user can proceed to the next page.
152
153        :return: True if one or more files are selected.
154        """
155        return self.file_selector_widget.get_selected_files()
156
157    def is_ready_to_go_back(self):
158        """
159        Check if the user can navigate backward.
160
161        :return: Always True for this page.
162        """
163        return True
164
165    def reset_page(self):
166        """
167        Reset the page to its initial state, clearing all selections and messages.
168        """
169        self.file_selector_widget._selected_files = []
170
171        self.status_label.setText("")
172
173        # Clear any saved data in the context
174        if self.context:
175            self.context["selected_segmentation_files"] = []
176
177    def _translate_ui(self):
178        """Apply translations to all text elements in the UI."""
179        self.title.setText(QCoreApplication.translate(
180            "DlSelectionPage",
181            "Select NIfTI files for Deep Learning Segmentation"
182        ))

GUI page that allows the user to select NIfTI files for Deep Learning-based segmentation.

This page is part of a multi-step workflow:

  • Displays a title and a FileSelectorWidget to pick one or more NIfTI files.
  • Checks if a segmentation already exists for a given subject.
  • Saves selections in a shared context and navigates to the next page (DlExecutionPage).
DlNiftiSelectionPage(context=None, previous_page=None)
28    def __init__(self, context=None, previous_page=None):
29        """
30        Initialize the patient selection page.
31
32        :param context: Shared application context dictionary (used for data persistence between pages)
33        :param previous_page: Reference to the previous Page object (for navigation)
34        """
35        super().__init__()
36        self.context = context
37        self.previous_page = previous_page
38        self.next_page = None  # Will be created when advancing
39
40        self._setup_ui()
41        self._translate_ui()
42
43        # Re-translate the UI dynamically if the language changes in the context
44        if context and "language_changed" in context:
45            context["language_changed"].connect(self._translate_ui)

Initialize the patient selection page.

Parameters
  • context: Shared application context dictionary (used for data persistence between pages)
  • previous_page: Reference to the previous Page object (for navigation)
context
previous_page
next_page
def has_existing_segmentation(self, nifti_file_path, workspace_path):
 77    def has_existing_segmentation(self, nifti_file_path, workspace_path):
 78        """
 79        Check if a deep learning segmentation already exists for the patient corresponding to this NIfTI file.
 80
 81        :param nifti_file_path: Full path to the selected NIfTI file.
 82        :param workspace_path: Root path of the working directory.
 83        :return: True if a segmentation file is already present, otherwise False.
 84        """
 85        # Extract patient ID (subject ID) from the NIfTI file path
 86        path_parts = nifti_file_path.replace(workspace_path, '').strip(os.sep).split(os.sep)
 87
 88        # Look for a directory segment starting with 'sub-' (BIDS convention)
 89        subject_id = None
 90        for part in path_parts:
 91            if part.startswith('sub-'):
 92                subject_id = part
 93                break
 94
 95        # If no subject identifier found, no segmentation can be associated
 96        if not subject_id:
 97            return False
 98
 99        # Expected directory where segmentations are stored
100        seg_dir = os.path.join(workspace_path, 'derivatives', 'deep_learning_seg', subject_id, 'anat')
101
102        # If the segmentation directory does not exist, return False
103        if not os.path.exists(seg_dir):
104            return False
105
106        # Check for any segmentation file in the directory
107        for file in os.listdir(seg_dir):
108            if file.endswith('_seg.nii.gz') or file.endswith('_seg.nii'):
109                return True
110
111        return False

Check if a deep learning segmentation already exists for the patient corresponding to this NIfTI file.

Parameters
  • nifti_file_path: Full path to the selected NIfTI file.
  • workspace_path: Root path of the working directory.
Returns

True if a segmentation file is already present, otherwise False.

def back(self):
113    def back(self):
114        """
115        Navigate back to the previous page in the workflow.
116
117        :return: The previous Page instance, or None if there is none.
118        """
119        if self.previous_page:
120            self.previous_page.on_enter()
121            return self.previous_page
122        return None

Navigate back to the previous page in the workflow.

Returns

The previous Page instance, or None if there is none.

def next(self, context):
124    def next(self, context):
125        """
126        Save the selected files in the context and move to the next page (DlExecutionPage).
127
128        :param context: The shared application context dictionary.
129        :return: The next Page instance.
130        """
131        # Store selected files in the context
132        if self.context is not None:
133            self.context["selected_segmentation_files"] = self.file_selector_widget.get_selected_files()
134
135        # Instantiate the next page only once
136        if not self.next_page:
137            self.next_page = DlExecutionPage(self.context, self)
138            if "history" in self.context:
139                self.context["history"].append(self.next_page)
140
141        # Prepare the next page before displaying
142        self.next_page.on_enter()
143        return self.next_page

Save the selected files in the context and move to the next page (DlExecutionPage).

Parameters
  • context: The shared application context dictionary.
Returns

The next Page instance.

def on_enter(self):
145    def on_enter(self):
146        """Called when the page is shown — resets transient UI elements."""
147        self.status_label.setText("")

Called when the page is shown — resets transient UI elements.

def is_ready_to_advance(self):
149    def is_ready_to_advance(self):
150        """
151        Check if the user can proceed to the next page.
152
153        :return: True if one or more files are selected.
154        """
155        return self.file_selector_widget.get_selected_files()

Check if the user can proceed to the next page.

Returns

True if one or more files are selected.

def is_ready_to_go_back(self):
157    def is_ready_to_go_back(self):
158        """
159        Check if the user can navigate backward.
160
161        :return: Always True for this page.
162        """
163        return True

Check if the user can navigate backward.

Returns

Always True for this page.

def reset_page(self):
165    def reset_page(self):
166        """
167        Reset the page to its initial state, clearing all selections and messages.
168        """
169        self.file_selector_widget._selected_files = []
170
171        self.status_label.setText("")
172
173        # Clear any saved data in the context
174        if self.context:
175            self.context["selected_segmentation_files"] = []

Reset the page to its initial state, clearing all selections and messages.