Source code for mdt.gui.model_fit.qt_main

import signal
import sys


from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QFileDialog, QMessageBox

from mdt.gui.model_fit.design.ui_about_dialog import Ui_AboutDialog
from mdt.gui.model_fit.design.ui_dialog_get_example_data import Ui_GetExampleDataDialog
from mdt.gui.model_fit.design.ui_runtime_settings_dialog import Ui_RuntimeSettingsDialog
from mdt.gui.model_fit.tabs.fit_model_tab import FitModelTab
from mdt.gui.model_fit.tabs.generate_brain_mask_tab import GenerateBrainMaskTab
from mdt.gui.model_fit.tabs.generate_roi_mask_tab import GenerateROIMaskTab

import mdt.utils
import mot.configuration
from mdt.configuration import update_gui_config
from mdt.gui.model_fit.tabs.generate_protocol_tab import GenerateProtocolTab
from mot.lib.cl_environments import CLEnvironmentFactory
from queue import Queue
from PyQt5 import QtGui
from PyQt5.QtCore import QThread, QTimer, pyqtSlot
from PyQt5.QtWidgets import QMainWindow, QDialog, QDialogButtonBox
from mdt.gui.model_fit.design.ui_main_gui import Ui_MainWindow
from mdt.gui.utils import print_welcome_message, ForwardingListener, MessageReceiver, center_window, QtManager, \
    enable_pyqt_exception_hook
from mdt.gui.model_fit.utils import SharedState
from mdt.lib.log_handlers import LogDispatchHandler

__author__ = 'Robbert Harms'
__date__ = "2016-06-26"
__maintainer__ = "Robbert Harms"
__email__ = "robbert@xkls.nl"


[docs]class MDTGUISingleModel(QMainWindow, Ui_MainWindow): def __init__(self, shared_state, computations_thread): super().__init__() self.setupUi(self) self._shared_state = shared_state self._computations_thread = computations_thread self._computations_thread.signal_starting.connect(self.computations_started) self._computations_thread.signal_finished.connect(self.computations_finished) self._stdout_old = sys.stdout self._stderr_old = sys.stderr self._logging_update_queue = Queue() self._logging_update_thread = QThread() self._message_receiver = MessageReceiver(self._logging_update_queue) self._message_receiver.text_message_signal.connect(self.update_log) self._message_receiver.moveToThread(self._logging_update_thread) self._logging_update_thread.started.connect(self._message_receiver.run) self._logging_update_thread.start() sys.stdout = ForwardingListener(self._logging_update_queue) sys.stderr = ForwardingListener(self._logging_update_queue) LogDispatchHandler.add_listener(ForwardingListener(self._logging_update_queue)) print_welcome_message() self.actionExit.setShortcuts(['Ctrl+q', 'Ctrl+w']) self.action_RuntimeSettings.triggered.connect(lambda: RuntimeSettingsDialog(self).exec_()) self.action_MapsVisualizer.triggered.connect(lambda: mdt.gui.maps_visualizer.main.start_gui(app_exec=False)) self.actionAbout.triggered.connect(lambda: AboutDialog(self).exec_()) self.action_GetExampleData.triggered.connect(lambda: GetExampleDataDialog(self, shared_state).exec_()) self.executionStatusLabel.setText('Idle') self.executionStatusIcon.setPixmap(QtGui.QPixmap(":/main_gui/icon_status_red.png")) self.fit_model_tab = FitModelTab(shared_state, self._computations_thread) self.fit_model_tab.setupUi(self.fitModelTab) self.generate_mask_tab = GenerateBrainMaskTab(shared_state, self._computations_thread) self.generate_mask_tab.setupUi(self.generateBrainMaskTab) self.generate_roi_mask_tab = GenerateROIMaskTab(shared_state, self._computations_thread) self.generate_roi_mask_tab.setupUi(self.generateROIMaskTab) self.generate_protocol_tab = GenerateProtocolTab(shared_state, self._computations_thread) self.generate_protocol_tab.setupUi(self.generateProtocolTab) self.tabs = [self.fit_model_tab, self.generate_mask_tab, self.generate_roi_mask_tab, self.generate_protocol_tab] self.MainTabs.currentChanged.connect(lambda index: self.tabs[index].tab_opened())
[docs] def closeEvent(self, event): sys.stdout = self._stdout_old sys.stderr = self._stderr_old self._message_receiver.is_running = False self._logging_update_thread.quit() self._logging_update_thread.wait(10) super().closeEvent(event)
[docs] def send_sigint(self, *args): self.close()
[docs] @pyqtSlot() def computations_started(self): self.executionStatusLabel.setText('Computing') self.executionStatusIcon.setPixmap(QtGui.QPixmap(":/main_gui/icon_status_green.png"))
[docs] @pyqtSlot() def computations_finished(self): self.executionStatusLabel.setText('Idle') self.executionStatusIcon.setPixmap(QtGui.QPixmap(":/main_gui/icon_status_red.png"))
[docs] @pyqtSlot(str) def update_log(self, string): sb = self.loggingTextBox.verticalScrollBar() scrollbar_position = sb.value() autoscroll = scrollbar_position == sb.maximum() self.loggingTextBox.moveCursor(QtGui.QTextCursor.End) self.loggingTextBox.insertPlainText(string) if autoscroll: sb.setValue(sb.maximum()) else: sb.setValue(scrollbar_position)
[docs]class RuntimeSettingsDialog(Ui_RuntimeSettingsDialog, QDialog): def __init__(self, parent): super().__init__(parent) self.setupUi(self) self.all_cl_devices = CLEnvironmentFactory.smart_device_selection() self.user_selected_devices = mot.configuration.get_cl_environments() self.cldevicesSelection.itemSelectionChanged.connect(self.selection_updated) self.cldevicesSelection.insertItems(0, [str(cl_device) for cl_device in self.all_cl_devices]) for ind, device in enumerate(self.all_cl_devices): self.cldevicesSelection.item(ind).setSelected(device in self.user_selected_devices and device in self.all_cl_devices) self.buttonBox.button(QDialogButtonBox.Ok).clicked.connect(self._update_settings)
[docs] @pyqtSlot() def selection_updated(self): self.buttonBox.button(QDialogButtonBox.Ok).setEnabled( any(self.cldevicesSelection.item(ind).isSelected() for ind in range(self.cldevicesSelection.count())))
def _update_settings(self): selection = [ind for ind in range(self.cldevicesSelection.count()) if self.cldevicesSelection.item(ind).isSelected()] mot.configuration.set_cl_environments([self.all_cl_devices[ind] for ind in selection]) update_gui_config({'runtime_settings': {'cl_device_ind': selection}})
[docs]class AboutDialog(Ui_AboutDialog, QDialog): def __init__(self, parent): super().__init__(parent) self.setupUi(self) self.contentLabel.setText(self.contentLabel.text().replace('{version}', mdt.__version__))
[docs]class GetExampleDataDialog(Ui_GetExampleDataDialog, QDialog): def __init__(self, parent, shared_state): super().__init__(parent) self._shared_state = shared_state self.setupUi(self) self.outputFileSelect.clicked.connect(lambda: self._select_output_folder()) self.outputFile.textChanged.connect(self._check_enable_ok_button) self.buttonBox.button(QDialogButtonBox.Ok).clicked.connect(self._write_example_data) self._check_enable_ok_button() def _write_example_data(self): try: mdt.utils.get_example_data(self.outputFile.text()) msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText('The MDT example data has been written to {}.'.format(self.outputFile.text())) msg.setWindowTitle('Success') msg.exec_() except IOError as e: msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText(str(e)) msg.setWindowTitle("File writing error") msg.exec_() def _select_output_folder(self): initial_dir = self._shared_state.base_dir if self.outputFile.text() != '': initial_dir = self.outputFile.text() output_dir = QFileDialog().getExistingDirectory( caption='Select the output folder', directory=initial_dir) if output_dir: self.outputFile.setText(output_dir) self._shared_state.base_dir = output_dir def _check_enable_ok_button(self): enabled = True if self.outputFile.text() == '': enabled = False self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enabled)
class ComputationsThread(QThread): signal_starting = pyqtSignal() signal_finished = pyqtSignal() def __init__(self, *args, **kwargs): """This is the thread handler for the computations. When running computations using this thread please connect signals to the starting and finished slot of this class. These handlers notify the main window of the computations. """ super().__init__(*args, **kwargs) @pyqtSlot() def starting(self): self.signal_starting.emit() @pyqtSlot() def finished(self): self.signal_finished.emit()
[docs]def start_gui(base_dir=None, app_exec=True): """Start the model fitting GUI. Args: base_dir (str): the starting directory for the file opening actions app_exec (boolean): if true we execute the Qt application, set to false to disable. """ try: mdt.configuration.load_user_gui() except IOError: pass enable_pyqt_exception_hook() app = QtManager.get_qt_application_instance() state = SharedState() state.base_dir = base_dir computations_thread = ComputationsThread() computations_thread.start() # catches the sigint timer = QTimer() timer.start(500) timer.timeout.connect(lambda: None) composite_model_gui = MDTGUISingleModel(state, computations_thread) signal.signal(signal.SIGINT, composite_model_gui.send_sigint) center_window(composite_model_gui) composite_model_gui.show() QtManager.add_window(composite_model_gui) if app_exec: QtManager.exec_()
if __name__ == '__main__': start_gui()