Source code for spinningdiskanalyzer.frontend.window

from .window_ui import Ui_window
from .pages     import Pages
from ..logger   import logs_folder
from ..         import parameters
from ..         import meta

from PySide6.QtWidgets import QMainWindow
from PySide6.QtWidgets import QMessageBox
from PySide6.QtWidgets import QWidget
from PySide6.QtGui     import QAction
from PySide6.QtGui     import QShortcut
from PySide6.QtGui     import QKeySequence
from PySide6.QtCore    import QEvent
from PySide6.QtCore    import Qt

from webbrowser import open as browse
from platform   import system
from subprocess import run
from pathlib    import Path
import os


[docs] class Window(QMainWindow): """Main window of the application""" def __init__(self, parent: QWidget = None): # Load user interface design created in Qt Designer. super().__init__(parent) self.ui = Ui_window() self.ui.setupUi(self) self.setFocusPolicy(Qt.ClickFocus) self.setWindowTitle(meta.title) # We only have one widget, which manages the various pages. self.pages = Pages() self.setCentralWidget(self.pages) # Make sure we get notified of status updates. self.pages.status_update.connect(self.ui.status.showMessage) self.pages.status_clear.connect(self.ui.status.clearMessage) # Add keyboard shortcuts. self.keys = [] key = QShortcut(QKeySequence('Esc'), self) key.activated.connect(self.close) self.keys.append(key) # Display all actions in the right-click context menu. self.setContextMenuPolicy(Qt.ActionsContextMenu) # Add context menu entries. action = QAction('About…', self) action.triggered.connect(self.show_about) action.setShortcut('Alt+A') self.addAction(action) action = QAction('Documentation…', self) action.triggered.connect(self.show_docs) action.setShortcut('F1') self.addAction(action) action = QAction('Edit parameters…', self) action.triggered.connect(self.edit_parameters) action.setShortcut('Alt+P') self.addAction(action) action = QAction('Edit defaults…', self) action.triggered.connect(self.edit_defaults) action.setShortcut('Alt+D') self.addAction(action) action = QAction('Debug logs…', self) action.triggered.connect(self.show_logs) action.setShortcut('Alt+L') self.addAction(action)
[docs] def show_about(self): """Displays the About dialog.""" text = (f'{meta.title} {meta.version}\n\n' f'{meta.synopsis}\n\n' f'Developed by Scientific IT Services of ETH Zurich.\n\n' f{meta.copyright}\n') QMessageBox.about(self, 'About', text)
[docs] def show_docs(self): """ Opens the documentation in the web browser. We prefer to show the documentation distributed with the packaged application, as it should then refer to the same version. But if for some unforeseen reason we cannot find that, we direct the user to the online version. """ here = Path(__file__).parent.resolve() files = ( here.parent.parent.parent/'docs'/'index.html', here.parent.parent/'build'/'docs'/'index.html', ) for file in files: if file.exists(): if system() == 'Darwin': run(f'open "{file}"', shell=True) else: browse(str(file)) # On Windows, we could pass the Path object directly. # But that didn't work on Linux Mint, hence the # explicit string conversion here. break else: browse(r'https://spinningdiskanalyzer.ethz.ch/')
[docs] def edit_parameters(self): """Opens the file with the processing parameters in an editor.""" if parameters.file: self.open_item(parameters.file) else: QMessageBox.critical(self, 'Error', 'The parameters have not been initialized yet.\n\n' 'A "parameters.yaml" file is created (in an "analysis" ' 'subfolder) once a valid input folder has been selected.')
[docs] def edit_defaults(self): """Opens the config file with the parameter defaults in an editor.""" self.open_item(parameters.defaults_file())
[docs] def show_logs(self): """Opens the folder with the log files.""" self.open_item(logs_folder())
[docs] def open_item(self, item: Path): """Opens a file or folder using the default application.""" if system() == 'Windows': os.startfile(item) elif system() == 'Linux': run(f'xdg-open "{item}"', shell=True) elif system() == 'Darwin': run(f'open "{item}"', shell=True) else: noun = 'files' if item.is_file() else 'folders' QMessageBox.information(self, 'Information', f'Opening {noun} not supported on this platform.\n\n' f'Open your file manager and navigate to this location:\n' f'\t{item}')
[docs] def closeEvent(self, event: QEvent): """ Called when user closes the window. Qt does not propagate the "close" event to child widgets. That is, they are not explicitly closed, by calling `.close()` on them, so don't get a say in whether terminating the application is a good idea right now. We do want that though, so we can determine that within the context of the pages, one of which might be running a background task. Therefore we implement the mechanism ourselves, asking each page to confirm. """ if self.pages.confirm_close(): event.accept() else: event.ignore()