preparation for 1.5.1

This commit is contained in:
2026-07-17 23:59:42 -07:00
parent 0680718398
commit 2b019c1bc0
11 changed files with 350 additions and 59 deletions
+82 -13
View File
@@ -43,7 +43,7 @@ from src.window.updateoptodes import UpdateOptodesWindow
from src.window.userguide import UserGuideWindow
from src.window.viewerlauncher import ViewerLauncherWidget
from src.window.welcome import WelcomeDialog
from src.shared.flaresbasewidget import ParamSection
from src.shared.flaresbasewidget import FilePickerWidget, ParamSection
from src.shared.shareddata import API_URL, API_URL_SECONDARY, APP_NAME, CURRENT_VERSION, PIPELINE_STAGES, PLATFORM_NAME
from updater import finish_update_if_needed, UpdateManager, LocalPendingUpdateCheckThread
@@ -91,7 +91,7 @@ SECTIONS = [
"title": "Trimming",
"params": [
{"name": "TRIM", "default": True, "type": bool, "help": "Should the start of the files be trimmed?"},
{"name": "SECONDS_TO_KEEP", "default": 5, "type": float, "depends_on": "TRIM", "help": "Seconds to keep at the beginning of all loaded snirf files before the first annotation/event occurs. Calculation is done seperatly on all loaded snirf files. Setting this to 0 will have the first annotation/event be at time point 0. Only used if TRIM is set to True."},
{"name": "SECONDS_TO_KEEP", "default": 5.0, "type": float, "depends_on": "TRIM", "help": "Seconds to keep at the beginning of all loaded snirf files before the first annotation/event occurs. Calculation is done seperatly on all loaded snirf files. Setting this to 0 will have the first annotation/event be at time point 0. Only used if TRIM is set to True."},
]
},
{
@@ -257,7 +257,8 @@ SECTIONS = [
{"name": "FIR_DELAYS", "default": 15, "type": range, "depends_on": "HRF_MODEL", "depends_value": "fir", "help": "In case of FIR design, yields the array of delays used in the FIR model (in scans)."},
{"name": "MIN_ONSET", "default": -24, "type": int, "help": "Minimal onset relative to frame times (in seconds)"},
{"name": "OVERSAMPLING", "default": 50, "type": int, "help": "Oversampling factor used in temporal convolutions."},
{"name": "REMOVE_EVENTS", "default": "None", "type": list, "help": "Remove events matching the names provided before generating the Design Matrix"},
# TODO: Re-implement this without causing a memory leak
# {"name": "REMOVE_EVENTS", "default": "None", "type": list, "help": "Remove events matching the names provided before generating the Design Matrix"},
{"name": "SHORT_CHANNEL_REGRESSION", "default": True, "type": bool, "depends_on": "SHORT_CHANNEL", "help": "Should short channel regression be used to create the design matrix? This will use the 'signal' from the short channel and regress it out of all other channels."},
]
},
@@ -272,7 +273,7 @@ SECTIONS = [
{
"title": "Region of Interest",
"params": [
{"name": "JSON_LOCATION", "default": "", "type": str, "help": "Location of the JSON file containing region of interest results for significance calculations."},
{"name": "JSON_LOCATION", "default": "", "type": "json_file", "help": "Location of the JSON file containing region of interest results for significance calculations."},
]
},
{
@@ -505,7 +506,7 @@ class MainApplication(QMainWindow):
self.missing_events_bypass = False
self.analysis_clearing_bypass = False
self.folding_bypass = False
self.json_location = r"C:\Users\tyler\Desktop\research\flares\regions.json"
self.json_location = ""
# Initialization to ensure that saving can occur
@@ -525,15 +526,13 @@ class MainApplication(QMainWindow):
self.files_failed = set() # set of failed file paths
self.files_results = {} # dict for successful results (if needed)
self.platform_suffix = "-" + PLATFORM_NAME
self.updater = UpdateManager(
main_window=self,
api_url=API_URL,
api_url_sec=API_URL_SECONDARY,
current_version=CURRENT_VERSION,
platform_name=PLATFORM_NAME,
platform_suffix=self.platform_suffix,
platform_suffix="-" + PLATFORM_NAME,
app_name=APP_NAME
)
@@ -546,7 +545,7 @@ class MainApplication(QMainWindow):
self.installEventFilter(self)
# Start local pending update check thread
self.local_check_thread = LocalPendingUpdateCheckThread(CURRENT_VERSION, self.platform_suffix, PLATFORM_NAME, APP_NAME)
self.local_check_thread = LocalPendingUpdateCheckThread(CURRENT_VERSION, "-" + PLATFORM_NAME, PLATFORM_NAME, APP_NAME)
self.local_check_thread.pending_update_found.connect(self.updater.on_pending_update_found)
self.local_check_thread.no_pending_update.connect(self.updater.on_no_pending_update)
self.local_check_thread.start()
@@ -617,7 +616,7 @@ class MainApplication(QMainWindow):
label_desc = QLabel('<a href="#">Why are these useful?</a>')
label_desc.setTextInteractionFlags(Qt.TextInteractionFlag.TextBrowserInteraction)
label_desc.linkActivated.connect(lambda: QMessageBox.information(None, "Info", "Parameter Info..."))
label_desc.linkActivated.connect(lambda: QMessageBox.information(None, f"Info - {APP_NAME.upper()} ", "Age: Used in determing the participants PPF.\nGender: Not currently used or implemented.\nGroup: Used to split participants into groups for comparisons between them."))
right_column_layout.addWidget(label_desc)
right_column_layout.addStretch()
self.right_column_widget.hide()
@@ -835,6 +834,23 @@ class MainApplication(QMainWindow):
and resets the memory heap.
"""
if hasattr(self, "result_process") and self.result_process and self.result_process.is_alive():
msg = QMessageBox(self)
msg.setWindowTitle(f"Confirm Clear - {APP_NAME.upper()}")
msg.setText("Data processing is currently active in the background. "
"Clearing now will forcefully kill all tasks and lose current progress.\n\n"
"Are you sure you want to proceed?")
msg.setStandardButtons(QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel)
msg.setDefaultButton(QMessageBox.StandardButton.Cancel)
response = msg.exec()
if response == QMessageBox.StandardButton.Ok:
self.cancel_task()
else:
return
self.top_left_widget.clear()
if hasattr(self, "last_clicked_bubble"):
@@ -898,6 +914,16 @@ class MainApplication(QMainWindow):
self.metadata_cache = {}
self.file_metadata = {}
if hasattr(self, "meta_fields"):
for field in self.meta_fields.values():
field.blockSignals(True)
field.clear()
field.blockSignals(False)
self.current_file = None
if hasattr(self, "selected_paths"): self.selected_paths = []
if hasattr(self, "selected_path"): self.selected_path = None
@@ -1176,9 +1202,20 @@ class MainApplication(QMainWindow):
file_cfg.read_string(DEFAULT_CONFIG)
self.sync_app_with_config()
self.update_sections(0)
QTimer.singleShot(100, self._show_reset_success_dialog)
def _show_reset_success_dialog(self):
"""Helper method triggered after the UI has completely finished redrawing."""
QMessageBox.information(
self,
"Reset Successful",
"All application settings have been successfully restored to their default values."
)
self.statusbar.showMessage("All settings have been reset to their default values.", 5000)
self.statusbar.showMessage("All settings have been reset to their default values.", 5000)
def sync_app_with_config(self):
"""Reads values from file_cfg and updates both internal variables and UI checkmarks."""
@@ -1418,6 +1455,8 @@ class MainApplication(QMainWindow):
project_data = sanitize(project_data)
self.add_to_recent_projects(os.path.normpath(filename))
self.saving_overlay = SavingOverlay(self)
self.saving_overlay.resize(self.size()) # Cover the main window
self.saving_overlay.show()
@@ -1582,6 +1621,12 @@ class MainApplication(QMainWindow):
widget.blockSignals(False)
widget.update()
elif isinstance(widget, FilePickerWidget):
widget.blockSignals(True)
widget.setText(str(value)) # Updates the internal QLineEdit text safely
widget.blockSignals(False)
widget.update()
# QComboBox (bool, list)
elif isinstance(widget, QComboBox):
widget.blockSignals(True)
@@ -1599,10 +1644,19 @@ class MainApplication(QMainWindow):
widget.blockSignals(False)
widget.update()
if hasattr(section_widget, 'check_if_changed'):
if isinstance(widget, (QLineEdit, FilePickerWidget)):
section_widget.check_if_changed(name, widget.text())
elif isinstance(widget, QComboBox):
section_widget.check_if_changed(name, widget.currentText())
elif isinstance(widget, QSpinBox):
section_widget.check_if_changed(name, widget.value())
# After restoring, make sure dependencies are updated
if hasattr(section_widget, 'update_dependencies'):
section_widget.update_dependencies()
#TODO: Update blue bold text too
# def show_files_as_bubbles(self, folder_paths):
@@ -1659,7 +1713,6 @@ class MainApplication(QMainWindow):
current_ui_config = {}
try:
for section in self.param_sections:
# This calls the get_param_values() method you shared earlier
section_values = section.get_param_values()
current_ui_config.update(section_values)
return current_ui_config
@@ -1839,6 +1892,19 @@ class MainApplication(QMainWindow):
self.top_left_widget.clear()
self.right_column_widget.hide()
target_path = bubble.file_path
if hasattr(self, 'file_metadata'):
self.file_metadata.pop(target_path, None)
if getattr(self, 'current_file', None) == target_path:
self.current_file = None
if hasattr(self, 'meta_fields'):
for field in self.meta_fields.values():
field.blockSignals(True)
field.clear()
field.blockSignals(False)
parent_layout = bubble.parent().layout()
if parent_layout is not None:
parent_layout.removeWidget(bubble)
@@ -2055,11 +2121,14 @@ class MainApplication(QMainWindow):
if self.folding_bypass:
all_params['FOLDING_BYP'] = True
self.json_location = all_params['JSON_LOCATION']
collected_data = {
"SNIRF_FILES": snirf_files,
"PARAMS": all_params, # add this line
"METADATA": self.get_all_metadata(), # optionally add metadata if needed
}
# Start processing
if current_process().name == 'MainProcess':
self.result_queue = Queue()