typos, standardization, and file association for project extensions
This commit is contained in:
@@ -21,7 +21,7 @@ from mne.io.base import BaseRaw
|
||||
from flares import aggregate_fnirs_group_geometry, plot_fir_model_results, brain_3d_visualization
|
||||
from src.shared.flaresbasewidget import InterGroupUIMixin, FlaresBaseWidget
|
||||
from src.shared.shareddata import APP_NAME
|
||||
from mne.io import BaseRaw
|
||||
|
||||
|
||||
PARAMETERIZED_INDEXES: dict[int, list[dict[str, Any]]] = {
|
||||
0: [
|
||||
@@ -81,7 +81,6 @@ PARAMETERIZED_INDEXES: dict[int, list[dict[str, Any]]] = {
|
||||
}
|
||||
|
||||
|
||||
|
||||
class InterGroupBrainImageWidget(InterGroupUIMixin, FlaresBaseWidget):
|
||||
def __init__(
|
||||
self,
|
||||
|
||||
@@ -39,7 +39,6 @@ PARAMETERIZED_INDEXES: dict[int, list[dict[str, Any]]] = {
|
||||
}
|
||||
|
||||
|
||||
|
||||
class InterGroupFunctionalConnectivityWidget(InterGroupUIMixin, FlaresBaseWidget):
|
||||
def __init__(
|
||||
self,
|
||||
|
||||
@@ -157,7 +157,6 @@ DESCRIPTION = """0. ROI vs. Zero (run_roi_second_level_analysis)
|
||||
|
||||
|
||||
class InterGroupStatsWidget(InterGroupUIMixin, FlaresBaseWidget):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
haemo_dict: dict[str | Path, BaseRaw],
|
||||
|
||||
@@ -87,7 +87,6 @@ PARAMETERIZED_INDEXES: dict[int, list[dict[str, Any]]] = {
|
||||
}
|
||||
|
||||
|
||||
|
||||
class ParticipantFunctionalConnectivityWidget(ParticipantUIMixin, FlaresBaseWidget):
|
||||
def __init__(
|
||||
self,
|
||||
@@ -106,7 +105,6 @@ class ParticipantFunctionalConnectivityWidget(ParticipantUIMixin, FlaresBaseWidg
|
||||
self.setup_participant_ui(["0 (Spectral Connectivity Epochs)", "1 (Envelope Correlation)", "2 (Betas)", "3 (Spectral Connectivity Epochs)",])
|
||||
|
||||
|
||||
|
||||
def process_request(self):
|
||||
request = self.get_common_request_data(PARAMETERIZED_INDEXES)
|
||||
if request is None:
|
||||
@@ -138,7 +136,6 @@ class ParticipantFunctionalConnectivityWidget(ParticipantUIMixin, FlaresBaseWidg
|
||||
print(f"Skipping {self.participant_map[file_path]}: Event '{selected_event}' not found.")
|
||||
continue
|
||||
|
||||
|
||||
for idx in selected_indexes:
|
||||
if idx == 0:
|
||||
|
||||
|
||||
@@ -85,7 +85,6 @@ class ParticipantImageViewerWidget(FlaresBaseWidget):
|
||||
self.showMaximized()
|
||||
|
||||
|
||||
|
||||
def show_selected_images(self):
|
||||
# Clear previous images
|
||||
while self.grid_layout.count():
|
||||
|
||||
@@ -7,11 +7,13 @@ Author: Tyler de Zeeuw
|
||||
License: GPL-3.0
|
||||
"""
|
||||
|
||||
# External library imports
|
||||
from PySide6.QtWidgets import QWidget, QVBoxLayout, QLabel
|
||||
from PySide6.QtCore import Qt
|
||||
|
||||
from src.shared.shareddata import APP_NAME, APP_NAME_EXPANDED, CURRENT_VERSION
|
||||
|
||||
|
||||
class AboutWindow(QWidget):
|
||||
"""
|
||||
Simple About window displaying basic application information.
|
||||
|
||||
+64
-2
@@ -7,16 +7,38 @@ Author: Tyler de Zeeuw
|
||||
License: GPL-3.0
|
||||
"""
|
||||
|
||||
# Built-in imports
|
||||
from typing import Any, Callable
|
||||
|
||||
# External library imports
|
||||
from PySide6.QtWidgets import QWidget, QVBoxLayout, QTextEdit, QLineEdit
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtCore import Qt, QThread, Signal
|
||||
|
||||
from file_ext_registration import register_file_association, is_windows_admin
|
||||
from src.shared.shareddata import API_URL, API_URL_SECONDARY, APP_NAME, CURRENT_VERSION, PLATFORM_NAME
|
||||
from src.window.about import AboutWindow
|
||||
from updater import UpdateManager
|
||||
|
||||
|
||||
class _AssocWorker(QThread):
|
||||
"""
|
||||
Runs register_file_association() off the UI thread. Only actually
|
||||
needed for the force_admin=True path, since that blocks on
|
||||
WaitForSingleObject while the UAC prompt is up and the elevated
|
||||
child process runs — which would otherwise freeze the terminal
|
||||
window. Used for the non-elevated path too for consistency.
|
||||
"""
|
||||
result_ready = Signal(bool, str)
|
||||
|
||||
def __init__(self, force_admin: bool, parent: QWidget | None = None) -> None:
|
||||
super().__init__(parent)
|
||||
self._force_admin = force_admin
|
||||
|
||||
def run(self) -> None:
|
||||
ok, msg = register_file_association(force_admin=self._force_admin)
|
||||
self.result_ready.emit(ok, msg)
|
||||
|
||||
|
||||
class TerminalWindow(QWidget):
|
||||
def __init__(self, parent: QWidget | None = None) -> None:
|
||||
super().__init__(parent, Qt.WindowType.Window)
|
||||
@@ -38,9 +60,13 @@ class TerminalWindow(QWidget):
|
||||
"help": self.cmd_help,
|
||||
"version": self.cmd_version,
|
||||
"about": self.cmd_about,
|
||||
"assoc": self.cmd_assoc,
|
||||
"update": self.cmd_update,
|
||||
}
|
||||
|
||||
self._pending_assoc_confirmation: bool = False
|
||||
self._assoc_worker: _AssocWorker | None = None
|
||||
|
||||
self.output_area.append(f"Welcome to {APP_NAME.upper()}. You are running version {CURRENT_VERSION}.")
|
||||
self.output_area.append("Type 'help' for a list of available commands.\n")
|
||||
|
||||
@@ -52,6 +78,12 @@ class TerminalWindow(QWidget):
|
||||
self.input_line.clear()
|
||||
|
||||
self.output_area.append(f"> {command_text}")
|
||||
|
||||
if self._pending_assoc_confirmation:
|
||||
self._pending_assoc_confirmation = False
|
||||
self._handle_assoc_confirmation(command_text.strip().lower())
|
||||
return
|
||||
|
||||
parts = command_text.strip().split()
|
||||
if not parts:
|
||||
return
|
||||
@@ -101,4 +133,34 @@ class TerminalWindow(QWidget):
|
||||
self.output_area.append("Checking for updates...")
|
||||
|
||||
self.updater.manual_check_for_updates()
|
||||
return "See status bar for update information."
|
||||
return "See status bar for update information."
|
||||
|
||||
def cmd_assoc(self, *args: Any) -> str | None:
|
||||
# Non-Windows platforms don't have the admin/non-admin split —
|
||||
# just register directly.
|
||||
if PLATFORM_NAME != "windows" or is_windows_admin():
|
||||
self._run_assoc(force_admin=False)
|
||||
return None
|
||||
|
||||
self._pending_assoc_confirmation = True
|
||||
return "Not running as admin. Register system-wide via UAC elevation? (y/n)"
|
||||
|
||||
def _handle_assoc_confirmation(self, answer: str) -> None:
|
||||
if answer in ("y", "yes"):
|
||||
self._run_assoc(force_admin=True)
|
||||
elif answer in ("n", "no"):
|
||||
self._run_assoc(force_admin=False)
|
||||
else:
|
||||
self.output_area.append("Please answer 'y' or 'n'. Run 'assoc' again to retry.")
|
||||
|
||||
def _run_assoc(self, force_admin: bool) -> None:
|
||||
if force_admin:
|
||||
self.output_area.append("Requesting elevation. Check for a UAC prompt...")
|
||||
|
||||
self._assoc_worker = _AssocWorker(force_admin=force_admin, parent=self)
|
||||
self._assoc_worker.result_ready.connect(self._on_assoc_result)
|
||||
self._assoc_worker.start()
|
||||
|
||||
def _on_assoc_result(self, ok: bool, msg: str) -> None:
|
||||
self.output_area.append(msg)
|
||||
self._assoc_worker = None
|
||||
@@ -1,11 +1,13 @@
|
||||
"""
|
||||
Filename: userguide.py
|
||||
Description: User guide for FLARES
|
||||
Description: User guide window
|
||||
Note: Compliant with pylance strict type checking
|
||||
|
||||
Author: Tyler de Zeeuw
|
||||
License: GPL-3.0
|
||||
"""
|
||||
|
||||
# External library imports
|
||||
from PySide6.QtWidgets import QWidget, QVBoxLayout, QLabel
|
||||
from PySide6.QtCore import Qt
|
||||
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
"""
|
||||
Filename: welcome.py
|
||||
Description: Welcome dialog for FLARES
|
||||
Description: Welcome dialog window
|
||||
Note: Compliant with pylance strict type checking
|
||||
|
||||
Author: Tyler de Zeeuw
|
||||
License: GPL-3.0
|
||||
"""
|
||||
|
||||
# External library imports
|
||||
from PySide6.QtWidgets import QTextBrowser, QVBoxLayout, QLabel, QDialog, QHBoxLayout, QPushButton
|
||||
from PySide6.QtGui import QDesktopServices, QIcon
|
||||
from PySide6.QtCore import QUrl
|
||||
from PySide6.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
|
||||
|
||||
from src.shared.shareddata import APP_NAME, CURRENT_VERSION, CHANGELOG_URL, resource_path
|
||||
from src.shared.shareddata import APP_NAME, PLATFORM_NAME, CURRENT_VERSION, CHANGELOG_URL, resource_path
|
||||
|
||||
|
||||
class WelcomeDialog(QDialog):
|
||||
@@ -27,8 +28,8 @@ class WelcomeDialog(QDialog):
|
||||
header_layout = QHBoxLayout()
|
||||
logo_label = QLabel(self)
|
||||
|
||||
# NOTE: might not work on mac and need the icns file
|
||||
logo_label.setPixmap(QIcon(resource_path("icons/main.ico")).pixmap(48, 48))
|
||||
icon_ext = "icns" if PLATFORM_NAME == "darwin" else "ico"
|
||||
logo_label.setPixmap(QIcon(resource_path(f"icons/main.{icon_ext}")).pixmap(48, 48))
|
||||
if first:
|
||||
title_label = QLabel(f"<h2>Welcome to {APP_NAME.upper()}!</h2>", self)
|
||||
elif direct:
|
||||
|
||||
Reference in New Issue
Block a user