Utils

Clear

Fully reset the GUI state and remove all in-memory data.

This helper: - Clears the active DataSet and GUI fields via clear_data. - Empties the console widget. - Writes a confirmation message to the GUI console.

Parameters

window : QMainWindow Main application window whose state should be cleared.

Source code in gui\utils\clear\clear_all.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
def clear_all(window: QtWidgets.QMainWindow):
    """
    Fully reset the GUI state and remove all in-memory data.

    This helper:
    - Clears the active `DataSet` and GUI fields via `clear_data`.
    - Empties the console widget.
    - Writes a confirmation message to the GUI console.

    Parameters
    ----------
    window : QMainWindow
        Main application window whose state should be cleared.
    """
    clear_data(window)
    window.consoleTextEdit.clear()
    window.console_print("Cleared memory")

Clear the currently loaded dataset and reset all GUI widgets tied to it.

Resets: - Stored DataSet object and its disk location. - Set name, device name, notes, and list widgets. - Plot type combobox and stacked widget view.

A console message is printed to confirm completion.

Parameters

window : QMainWindow Main GUI instance that holds dataset-related widgets.

Source code in gui\utils\clear\clear_data.py
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def clear_data(window: QtWidgets.QMainWindow):
    """
    Clear the currently loaded dataset and reset all GUI widgets tied to it.

    Resets:
    - Stored `DataSet` object and its disk location.
    - Set name, device name, notes, and list widgets.
    - Plot type combobox and stacked widget view.

    A console message is printed to confirm completion.

    Parameters
    ----------
    window : QMainWindow
        Main GUI instance that holds dataset-related widgets.
    """
    window.dataset = None
    window.dataset_location = None

    window.currSetNameLineEdit.clear()
    window.currDeviceLineEdit.clear()
    window.notesPlainText.clear()
    window.console_print("Cleared dataset from memory")

    window.stackedWidget.setCurrentWidget(window.stackedWidget.widget(0))
    window.selectedFilesList.clear()
    window.plotTypeCombo.clear()

DataSet Tools

Launch the DataSet creation dialog and construct a new dataset from user input.

Workflow: - Opens the DataSet creator window populated with available devices. - On confirmation: * Clears existing state. * Stores the newly created dataset. * Loads it into the GUI and updates the header. * Immediately saves it to disk. - If cancelled, informs the user that no dataset was created.

Parameters

window : QMainWindow Main application window controlling dataset creation.

Source code in gui\utils\dataset_tools\create_dataset.py
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@with_logging
def create_dataset(window: QtWidgets.QMainWindow, *args, **kwargs):
    """
    Launch the DataSet creation dialog and construct a new dataset from user input.

    Workflow:
    - Opens the DataSet creator window populated with available devices.
    - On confirmation:
        * Clears existing state.
        * Stores the newly created dataset.
        * Loads it into the GUI and updates the header.
        * Immediately saves it to disk.
    - If cancelled, informs the user that no dataset was created.

    Parameters
    ----------
    window : QMainWindow
        Main application window controlling dataset creation.
    """
    window.set_dataset_window(gui.windows.DataSetCreatorWindow.UiDataCreatorWindow(devices = [k for k in window.devices]))
    window.get_dataset_window().show()

    if window.dataWindow.exec() == 1:
        # If the window was properly closed (Done button) then creation was successful
        #     Copy dataset_tools and print to console
        clear_data(window)
        window.set_dataset(window.get_dataset_window().get_dataset())
        window.console_print(f"DataSet file created")
        load_dataset(window)
        window.update_header()
        save_dataset(window)
    else:
        # Warn user that window was improperly closed and that no dataset_tools was created
        window.console_print("No DataSet file was created")

Populate the GUI with data from the currently loaded dataset.

Actions: - Adds all dataset labels to the file selection list. - Selects all items by default. - Populates the plot-type combobox with device-appropriate plotting functions.

Raises

IncompatibleDeviceTypeFound If the dataset’s device type does not match available plot handlers.

Parameters

window : QMainWindow GUI instance holding a loaded dataset.

Source code in gui\utils\dataset_tools\load_dataset.py
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
@with_logging
def load_dataset(window: QtWidgets.QMainWindow):
    """
    Populate the GUI with data from the currently loaded dataset.

    Actions:
    - Adds all dataset labels to the file selection list.
    - Selects all items by default.
    - Populates the plot-type combobox with device-appropriate plotting functions.

    Raises
    ------
    IncompatibleDeviceTypeFound
        If the dataset’s device type does not match available plot handlers.

    Parameters
    ----------
    window : QMainWindow
        GUI instance holding a loaded dataset.
    """
    # Add all top level keys to the selection list of the gui
    for label in window.dataset.get_labels():
        window.selectedFilesList.addItem(label)

    # FEATURE REQUEST: Make this a setting
    # Select all items by default
    window.selectedFilesList.selectAll()

    # Edit combobox to show all available plot types
    try:
        for function in window.get_plot_functions(window.get_current_device()):
            window.plotTypeCombo.addItem(function)

    except KeyError:
        window.console_print(
            f"Incompatible device type [{window.get_current_device()}] found in {window.get_dataset_name()}, select another dataset or implement the device type. DataSet path: N/A")
        raise IncompatibleDeviceTypeFound

    window.console_print("DataSet loaded")

Save the currently loaded dataset to disk using a file dialog.

Behaviour: - Ensures a dataset is loaded before saving. - Opens a save-file dialog and writes the dataset via DataSetJSONEncoder. - Auto-appends a valid extension if necessary. - Updates the stored dataset location and logs status messages.

Parameters

window : QMainWindow GUI window containing the active dataset.

Source code in gui\utils\dataset_tools\save_dataset.py
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
@with_logging
def save_dataset(window: QtWidgets.QMainWindow, *args, **kwargs):
    """
    Save the currently loaded dataset to disk using a file dialog.

    Behaviour:
    - Ensures a dataset is loaded before saving.
    - Opens a save-file dialog and writes the dataset via `DataSetJSONEncoder`.
    - Auto-appends a valid extension if necessary.
    - Updates the stored dataset location and logs status messages.

    Parameters
    ----------
    window : QMainWindow
        GUI window containing the active dataset.
    """

    # Make sure there is a dataset to save
    if window.get_dataset_name() is None:
        return window.console_print("Err: Must first load dataset", level="warning")

    # Run the file dialog
    # TODO: There's a bug in ubuntu 24 that has the filter reinitialised when navigating the path
    file_name = QtWidgets.QFileDialog.getSaveFileName(
        parent=window,
        caption="Save file to disk",
        filter="DataSets (*.json *.dataset *.ds);;All (*)",
        initialFilter="DataSets (*.json *.dataset *.ds)"
    )[0]

    if file_name != "":
        # Ensure the file name has a valid extension
        if file_name:
            if not any(file_name.endswith(ext) for ext in ('.json', '.dataset', '.ds')):
                # Default to .dataset if no valid extension
                file_name += '.ds'

        with open(file_name, "w") as json_file:
            current_dataset = window.get_dataset()
            json.dump(current_dataset, json_file, cls=fs.DataSetJSONEncoder)
            current_dataset.set_location(file_name)
        json_file.close()

        return window.console_print(f"Saved dataset file to {file_name}")
    else:
        # File dialog was exited without choosing a file
        return window.console_print(f"No file selected")

Other

Extract the current value from common Qt widget types.

Supported widgets: - QDoubleSpinBox / QSpinBox → numeric value - QCheckBox → boolean isChecked - QLineEdit / QComboBox → text, with "None"/"none" mapped to None

Raises NotImplementedError if the widget type is unsupported.

Parameters

widget : QWidget The widget whose value should be extracted.

Returns

Any The widget's value in a Python-friendly type.

Source code in gui\utils\get_qwidget_value.py
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
def get_qwidget_value(widget):
    """
    Extract the current value from common Qt widget types.

    Supported widgets:
    - QDoubleSpinBox / QSpinBox → numeric value
    - QCheckBox → boolean `isChecked`
    - QLineEdit / QComboBox → text, with "None"/"none" mapped to `None`

    Raises `NotImplementedError` if the widget type is unsupported.

    Parameters
    ----------
    widget : QWidget
        The widget whose value should be extracted.

    Returns
    -------
    Any
        The widget's value in a Python-friendly type.
    """
    if not isinstance(widget, QtWidgets.QWidget):
        raise ValueError("Input must be a QWidget instance")

    if isinstance(widget, QtWidgets.QDoubleSpinBox) or isinstance(widget, QtWidgets.QSpinBox):
        return widget.value()
    elif isinstance(widget, QtWidgets.QCheckBox):
        return widget.isChecked()
    elif isinstance(widget, QtWidgets.QLineEdit):
        return _cast_none_string_to_none_type(widget.text())
    elif isinstance(widget, QtWidgets.QComboBox):
        return _cast_none_string_to_none_type(widget.currentText())
    else:
        raise NotImplementedError(f"Widget type {type(widget)} not supported")

Find and return the checked QRadioButton within a dialog.

Scans all child radio buttons and returns the first active one.

Parameters

dialog : QDialog Container widget containing radio buttons.

Returns

QRadioButton or None The checked radio button, or None if no selection exists.

Source code in gui\utils\search_for_first_active_radio_button.py
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
def search_for_first_active_radio_button(dialog: QtWidgets.QDialog) -> QtWidgets.QRadioButton:
    """
    Find and return the checked QRadioButton within a dialog.

    Scans all child radio buttons and returns the first active one.

    Parameters
    ----------
    dialog : QDialog
        Container widget containing radio buttons.

    Returns
    -------
    QRadioButton or None
        The checked radio button, or `None` if no selection exists.
    """
    for radio_button in dialog.findChildren(QtWidgets.QRadioButton):
        if radio_button.isChecked():
            return radio_button
    return None

Split a CamelCase string into its component words.

Examples

"MyPlotType" → ["My", "Plot", "Type"]

Parameters

camel_case : str Input CamelCase string.

Returns

list[str] List of lowercase/uppercase-correct word segments.

Source code in gui\utils\split_camelCase.py
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
def split_camel_case(camel_case) -> list[str]:
    """
    Split a CamelCase string into its component words.

    Examples
    --------
    "MyPlotType" → ["My", "Plot", "Type"]

    Parameters
    ----------
    camel_case : str
        Input CamelCase string.

    Returns
    -------
    list[str]
        List of lowercase/uppercase-correct word segments.
    """
    return re.findall(r'[A-Z]?[a-z]+|[A-Z]+(?=[A-Z]|$)', camel_case)