ui.nifti_mask_selection_page

  1from PyQt6.QtWidgets import (QVBoxLayout, QLabel, QPushButton)
  2from PyQt6.QtCore import Qt, QCoreApplication
  3import os
  4
  5from components.file_selector_widget import FileSelectorWidget
  6from page import Page
  7from logger import get_logger
  8
  9log = get_logger()
 10
 11
 12class MaskNiftiSelectionPage(Page):
 13    """
 14    A page that allows the user to select a NIfTI file for automatic drawing (mask creation).
 15
 16    This page provides an interface for selecting a NIfTI file and checking
 17    if a corresponding mask already exists in the workspace directory.
 18    """
 19
 20    def __init__(self, context=None, previous_page=None):
 21        """
 22        Initialize the NiftiMaskSelectionPage.
 23
 24        Args:
 25            context (dict, optional): Shared context object used for communication
 26                between pages and the main controller.
 27            previous_page (Page, optional): The previous page in the navigation flow.
 28        """
 29        super().__init__()
 30        self.context = context
 31        self.previous_page = previous_page
 32        self.next_page = None
 33        self.selected_file = None
 34
 35        # Set up the main layout
 36        self.layout = QVBoxLayout(self)
 37        self.setLayout(self.layout)
 38
 39        # Title label
 40        self.title = QLabel("Select a NIfTI file for Automatic Drawing")
 41        self.title.setStyleSheet("font-size: 18px; font-weight: bold;")
 42        self.title.setAlignment(Qt.AlignmentFlag.AlignCenter)
 43        self.layout.addWidget(self.title)
 44
 45        # File selection widget
 46        self.file_selector_widget = FileSelectorWidget(
 47            parent=self,
 48            context=self.context,
 49            has_existing_function=self.has_existing_mask,
 50            label="mask",
 51            allow_multiple=False
 52        )
 53        self.layout.addWidget(self.file_selector_widget)
 54
 55        # Push everything to the top
 56        self.layout.addStretch()
 57
 58        # Button to open the NIfTI viewer
 59        self.viewer_button = QPushButton("Open NIfTI file")
 60        self.file_selector_widget.has_file.connect(self.viewer_button.setEnabled)
 61        self.viewer_button.setEnabled(False)
 62        self.viewer_button.clicked.connect(self.open_nifti_viewer)
 63        self.layout.addWidget(self.viewer_button)
 64
 65        # Translation setup for UI text
 66        self._translate_ui()
 67        if context and "language_changed" in context:
 68            context["language_changed"].connect(self._translate_ui)
 69
 70    def has_existing_mask(self, nifti_file_path, workspace_path):
 71        """
 72        Check if a manual or deep learning mask already exists for the selected NIfTI file.
 73
 74        Args:
 75            nifti_file_path (str): Full path to the NIfTI file.
 76            workspace_path (str): Root workspace directory.
 77
 78        Returns:
 79            bool: True if a mask file exists, False otherwise.
 80        """
 81        # Extract the subject ID (assuming a path structure like .../sub-XX/anat/sub-XX_modality.nii.gz)
 82        path_parts = nifti_file_path.replace(workspace_path, '').strip(os.sep).split(os.sep)
 83
 84        subject_id = None
 85        for part in path_parts:
 86            if part.startswith('sub-'):
 87                subject_id = part
 88                break
 89
 90        # If no subject ID is found, assume no mask exists
 91        if not subject_id:
 92            return False
 93
 94        # Build expected paths for manual and deep learning masks
 95        manual_mask_dir = os.path.join(workspace_path, 'derivatives', 'manual_masks', subject_id, 'anat')
 96        deep_learning_mask_dir = os.path.join(workspace_path, 'derivatives', 'deep_learning_masks', subject_id, 'anat')
 97
 98        # If neither directory exists, no mask can exist
 99        if not os.path.exists(manual_mask_dir) and not os.path.exists(deep_learning_mask_dir):
100            return False
101
102        # Check for existing NIfTI mask files (.nii.gz)
103        has_nii = False
104
105        if os.path.exists(manual_mask_dir):
106            for file in os.listdir(manual_mask_dir):
107                if file.endswith('.nii.gz'):
108                    has_nii = True
109                    break
110
111        if os.path.exists(deep_learning_mask_dir):
112            for file in os.listdir(deep_learning_mask_dir):
113                if file.endswith('.nii.gz'):
114                    has_nii = True
115                    break
116
117        return has_nii
118
119    def is_ready_to_advance(self):
120        """Return False because this page does not support advancing to the next page."""
121        return False
122
123    def is_ready_to_go_back(self):
124        """Always allow navigating back to the previous page."""
125        return True
126
127    def on_enter(self):
128        """Hook called when entering the page (currently does nothing)."""
129        pass
130
131    def open_nifti_viewer(self):
132        """
133        Open the selected NIfTI file in the external viewer defined in the context.
134
135        This method retrieves the selected file and invokes the
136        'open_nifti_viewer' function stored in the shared context.
137        """
138        try:
139            file = self.file_selector_widget.get_selected_files()[-1]
140            self.context["open_nifti_viewer"](file)
141        except Exception:
142            log.exception("Error while opening NIfTI viewer")
143
144    def back(self):
145        """
146        Navigate back to the previous page in the workflow.
147
148        Returns:
149            Page | None: The previous page if available, otherwise None.
150        """
151        if self.previous_page:
152            self.previous_page.on_enter()
153            return self.previous_page
154        return None
155
156    def reset_page(self):
157        """
158        Reset the page to its initial state.
159
160        Clears all file selections and disables the viewer button.
161        """
162        self.selected_file = None
163        self.file_selector_widget.clear_selected_files()
164        self.viewer_button.setEnabled(False)
165
166    def _translate_ui(self):
167        """
168        Update all user-facing text for language changes.
169
170        This method uses Qt’s translation system to localize labels and buttons.
171        """
172        self.title.setText(QCoreApplication.translate(
173            "NiftiMaskSelectionPage", "Select a NIfTI file for Automatic Drawing"
174        ))
175        self.viewer_button.setText(QCoreApplication.translate(
176            "NiftiMaskSelectionPage", "Open NIfTI file"
177        ))
log = <Logger GliAAns-UI (WARNING)>
class MaskNiftiSelectionPage(page.Page):
 13class MaskNiftiSelectionPage(Page):
 14    """
 15    A page that allows the user to select a NIfTI file for automatic drawing (mask creation).
 16
 17    This page provides an interface for selecting a NIfTI file and checking
 18    if a corresponding mask already exists in the workspace directory.
 19    """
 20
 21    def __init__(self, context=None, previous_page=None):
 22        """
 23        Initialize the NiftiMaskSelectionPage.
 24
 25        Args:
 26            context (dict, optional): Shared context object used for communication
 27                between pages and the main controller.
 28            previous_page (Page, optional): The previous page in the navigation flow.
 29        """
 30        super().__init__()
 31        self.context = context
 32        self.previous_page = previous_page
 33        self.next_page = None
 34        self.selected_file = None
 35
 36        # Set up the main layout
 37        self.layout = QVBoxLayout(self)
 38        self.setLayout(self.layout)
 39
 40        # Title label
 41        self.title = QLabel("Select a NIfTI file for Automatic Drawing")
 42        self.title.setStyleSheet("font-size: 18px; font-weight: bold;")
 43        self.title.setAlignment(Qt.AlignmentFlag.AlignCenter)
 44        self.layout.addWidget(self.title)
 45
 46        # File selection widget
 47        self.file_selector_widget = FileSelectorWidget(
 48            parent=self,
 49            context=self.context,
 50            has_existing_function=self.has_existing_mask,
 51            label="mask",
 52            allow_multiple=False
 53        )
 54        self.layout.addWidget(self.file_selector_widget)
 55
 56        # Push everything to the top
 57        self.layout.addStretch()
 58
 59        # Button to open the NIfTI viewer
 60        self.viewer_button = QPushButton("Open NIfTI file")
 61        self.file_selector_widget.has_file.connect(self.viewer_button.setEnabled)
 62        self.viewer_button.setEnabled(False)
 63        self.viewer_button.clicked.connect(self.open_nifti_viewer)
 64        self.layout.addWidget(self.viewer_button)
 65
 66        # Translation setup for UI text
 67        self._translate_ui()
 68        if context and "language_changed" in context:
 69            context["language_changed"].connect(self._translate_ui)
 70
 71    def has_existing_mask(self, nifti_file_path, workspace_path):
 72        """
 73        Check if a manual or deep learning mask already exists for the selected NIfTI file.
 74
 75        Args:
 76            nifti_file_path (str): Full path to the NIfTI file.
 77            workspace_path (str): Root workspace directory.
 78
 79        Returns:
 80            bool: True if a mask file exists, False otherwise.
 81        """
 82        # Extract the subject ID (assuming a path structure like .../sub-XX/anat/sub-XX_modality.nii.gz)
 83        path_parts = nifti_file_path.replace(workspace_path, '').strip(os.sep).split(os.sep)
 84
 85        subject_id = None
 86        for part in path_parts:
 87            if part.startswith('sub-'):
 88                subject_id = part
 89                break
 90
 91        # If no subject ID is found, assume no mask exists
 92        if not subject_id:
 93            return False
 94
 95        # Build expected paths for manual and deep learning masks
 96        manual_mask_dir = os.path.join(workspace_path, 'derivatives', 'manual_masks', subject_id, 'anat')
 97        deep_learning_mask_dir = os.path.join(workspace_path, 'derivatives', 'deep_learning_masks', subject_id, 'anat')
 98
 99        # If neither directory exists, no mask can exist
100        if not os.path.exists(manual_mask_dir) and not os.path.exists(deep_learning_mask_dir):
101            return False
102
103        # Check for existing NIfTI mask files (.nii.gz)
104        has_nii = False
105
106        if os.path.exists(manual_mask_dir):
107            for file in os.listdir(manual_mask_dir):
108                if file.endswith('.nii.gz'):
109                    has_nii = True
110                    break
111
112        if os.path.exists(deep_learning_mask_dir):
113            for file in os.listdir(deep_learning_mask_dir):
114                if file.endswith('.nii.gz'):
115                    has_nii = True
116                    break
117
118        return has_nii
119
120    def is_ready_to_advance(self):
121        """Return False because this page does not support advancing to the next page."""
122        return False
123
124    def is_ready_to_go_back(self):
125        """Always allow navigating back to the previous page."""
126        return True
127
128    def on_enter(self):
129        """Hook called when entering the page (currently does nothing)."""
130        pass
131
132    def open_nifti_viewer(self):
133        """
134        Open the selected NIfTI file in the external viewer defined in the context.
135
136        This method retrieves the selected file and invokes the
137        'open_nifti_viewer' function stored in the shared context.
138        """
139        try:
140            file = self.file_selector_widget.get_selected_files()[-1]
141            self.context["open_nifti_viewer"](file)
142        except Exception:
143            log.exception("Error while opening NIfTI viewer")
144
145    def back(self):
146        """
147        Navigate back to the previous page in the workflow.
148
149        Returns:
150            Page | None: The previous page if available, otherwise None.
151        """
152        if self.previous_page:
153            self.previous_page.on_enter()
154            return self.previous_page
155        return None
156
157    def reset_page(self):
158        """
159        Reset the page to its initial state.
160
161        Clears all file selections and disables the viewer button.
162        """
163        self.selected_file = None
164        self.file_selector_widget.clear_selected_files()
165        self.viewer_button.setEnabled(False)
166
167    def _translate_ui(self):
168        """
169        Update all user-facing text for language changes.
170
171        This method uses Qt’s translation system to localize labels and buttons.
172        """
173        self.title.setText(QCoreApplication.translate(
174            "NiftiMaskSelectionPage", "Select a NIfTI file for Automatic Drawing"
175        ))
176        self.viewer_button.setText(QCoreApplication.translate(
177            "NiftiMaskSelectionPage", "Open NIfTI file"
178        ))

A page that allows the user to select a NIfTI file for automatic drawing (mask creation).

This page provides an interface for selecting a NIfTI file and checking if a corresponding mask already exists in the workspace directory.

MaskNiftiSelectionPage(context=None, previous_page=None)
21    def __init__(self, context=None, previous_page=None):
22        """
23        Initialize the NiftiMaskSelectionPage.
24
25        Args:
26            context (dict, optional): Shared context object used for communication
27                between pages and the main controller.
28            previous_page (Page, optional): The previous page in the navigation flow.
29        """
30        super().__init__()
31        self.context = context
32        self.previous_page = previous_page
33        self.next_page = None
34        self.selected_file = None
35
36        # Set up the main layout
37        self.layout = QVBoxLayout(self)
38        self.setLayout(self.layout)
39
40        # Title label
41        self.title = QLabel("Select a NIfTI file for Automatic Drawing")
42        self.title.setStyleSheet("font-size: 18px; font-weight: bold;")
43        self.title.setAlignment(Qt.AlignmentFlag.AlignCenter)
44        self.layout.addWidget(self.title)
45
46        # File selection widget
47        self.file_selector_widget = FileSelectorWidget(
48            parent=self,
49            context=self.context,
50            has_existing_function=self.has_existing_mask,
51            label="mask",
52            allow_multiple=False
53        )
54        self.layout.addWidget(self.file_selector_widget)
55
56        # Push everything to the top
57        self.layout.addStretch()
58
59        # Button to open the NIfTI viewer
60        self.viewer_button = QPushButton("Open NIfTI file")
61        self.file_selector_widget.has_file.connect(self.viewer_button.setEnabled)
62        self.viewer_button.setEnabled(False)
63        self.viewer_button.clicked.connect(self.open_nifti_viewer)
64        self.layout.addWidget(self.viewer_button)
65
66        # Translation setup for UI text
67        self._translate_ui()
68        if context and "language_changed" in context:
69            context["language_changed"].connect(self._translate_ui)

Initialize the NiftiMaskSelectionPage.

Args: context (dict, optional): Shared context object used for communication between pages and the main controller. previous_page (Page, optional): The previous page in the navigation flow.

context
previous_page
next_page
selected_file
def layout(unknown):
title
file_selector_widget
viewer_button
def has_existing_mask(self, nifti_file_path, workspace_path):
 71    def has_existing_mask(self, nifti_file_path, workspace_path):
 72        """
 73        Check if a manual or deep learning mask already exists for the selected NIfTI file.
 74
 75        Args:
 76            nifti_file_path (str): Full path to the NIfTI file.
 77            workspace_path (str): Root workspace directory.
 78
 79        Returns:
 80            bool: True if a mask file exists, False otherwise.
 81        """
 82        # Extract the subject ID (assuming a path structure like .../sub-XX/anat/sub-XX_modality.nii.gz)
 83        path_parts = nifti_file_path.replace(workspace_path, '').strip(os.sep).split(os.sep)
 84
 85        subject_id = None
 86        for part in path_parts:
 87            if part.startswith('sub-'):
 88                subject_id = part
 89                break
 90
 91        # If no subject ID is found, assume no mask exists
 92        if not subject_id:
 93            return False
 94
 95        # Build expected paths for manual and deep learning masks
 96        manual_mask_dir = os.path.join(workspace_path, 'derivatives', 'manual_masks', subject_id, 'anat')
 97        deep_learning_mask_dir = os.path.join(workspace_path, 'derivatives', 'deep_learning_masks', subject_id, 'anat')
 98
 99        # If neither directory exists, no mask can exist
100        if not os.path.exists(manual_mask_dir) and not os.path.exists(deep_learning_mask_dir):
101            return False
102
103        # Check for existing NIfTI mask files (.nii.gz)
104        has_nii = False
105
106        if os.path.exists(manual_mask_dir):
107            for file in os.listdir(manual_mask_dir):
108                if file.endswith('.nii.gz'):
109                    has_nii = True
110                    break
111
112        if os.path.exists(deep_learning_mask_dir):
113            for file in os.listdir(deep_learning_mask_dir):
114                if file.endswith('.nii.gz'):
115                    has_nii = True
116                    break
117
118        return has_nii

Check if a manual or deep learning mask already exists for the selected NIfTI file.

Args: nifti_file_path (str): Full path to the NIfTI file. workspace_path (str): Root workspace directory.

Returns: bool: True if a mask file exists, False otherwise.

def is_ready_to_advance(self):
120    def is_ready_to_advance(self):
121        """Return False because this page does not support advancing to the next page."""
122        return False

Return False because this page does not support advancing to the next page.

def is_ready_to_go_back(self):
124    def is_ready_to_go_back(self):
125        """Always allow navigating back to the previous page."""
126        return True

Always allow navigating back to the previous page.

def on_enter(self):
128    def on_enter(self):
129        """Hook called when entering the page (currently does nothing)."""
130        pass

Hook called when entering the page (currently does nothing).

def open_nifti_viewer(self):
132    def open_nifti_viewer(self):
133        """
134        Open the selected NIfTI file in the external viewer defined in the context.
135
136        This method retrieves the selected file and invokes the
137        'open_nifti_viewer' function stored in the shared context.
138        """
139        try:
140            file = self.file_selector_widget.get_selected_files()[-1]
141            self.context["open_nifti_viewer"](file)
142        except Exception:
143            log.exception("Error while opening NIfTI viewer")

Open the selected NIfTI file in the external viewer defined in the context.

This method retrieves the selected file and invokes the 'open_nifti_viewer' function stored in the shared context.

def back(self):
145    def back(self):
146        """
147        Navigate back to the previous page in the workflow.
148
149        Returns:
150            Page | None: The previous page if available, otherwise None.
151        """
152        if self.previous_page:
153            self.previous_page.on_enter()
154            return self.previous_page
155        return None

Navigate back to the previous page in the workflow.

Returns: Page | None: The previous page if available, otherwise None.

def reset_page(self):
157    def reset_page(self):
158        """
159        Reset the page to its initial state.
160
161        Clears all file selections and disables the viewer button.
162        """
163        self.selected_file = None
164        self.file_selector_widget.clear_selected_files()
165        self.viewer_button.setEnabled(False)

Reset the page to its initial state.

Clears all file selections and disables the viewer button.