class FocusPresenter(object): def __init__(self, model, view): self.model = model self.view = view self.worker = None self.calibration_observer = CalibrationObserver(self) # Observable Setup self.focus_run_notifier = GenericObservable() # Connect view signals to local methods. self.view.set_on_focus_clicked(self.on_focus_clicked) self.view.set_enable_controls_connection( self.set_focus_controls_enabled) # Variables from other GUI tabs. self.current_calibration = CalibrationInfo() self.instrument = "ENGINX" self.rb_num = None last_van_path = get_setting(output_settings.INTERFACES_SETTINGS_GROUP, output_settings.ENGINEERING_PREFIX, "last_vanadium_run") if last_van_path: self.view.set_van_file_text_with_search(last_van_path) def add_focus_subscriber(self, obs): self.focus_run_notifier.add_subscriber(obs) def on_focus_clicked(self): if not self._validate(): return regions_dict = self.current_calibration.create_focus_roi_dictionary() focus_paths = self.view.get_focus_filenames() van_path = self.view.get_vanadium_filename() if self._number_of_files_warning(focus_paths): self.start_focus_worker(focus_paths, van_path, self.view.get_plot_output(), self.rb_num, regions_dict) van_run = self.view.get_vanadium_run() set_setting(output_settings.INTERFACES_SETTINGS_GROUP, output_settings.ENGINEERING_PREFIX, "last_vanadium_run", van_run) def start_focus_worker(self, focus_paths: list, van_path: str, plot_output: bool, rb_num: str, regions_dict: dict) -> None: """ Focus data in a separate thread to stop the main GUI from hanging. :param focus_paths: List of paths to the files containing the data to focus. :param plot_output: True if the output should be plotted. :param rb_num: The RB Number from the main window (often an experiment id) :param regions_dict: Dictionary containing the regions to focus over, mapping region_name -> grouping_ws_name """ self.worker = AsyncTask(self.model.focus_run, (focus_paths, van_path, plot_output, self.instrument, rb_num, regions_dict), error_cb=self._on_worker_error, finished_cb=self._on_worker_success) self.set_focus_controls_enabled(False) self.worker.start() def _on_worker_success(self): self.emit_enable_button_signal() self.focus_run_notifier.notify_subscribers( self.model.get_last_focused_files()) def set_instrument_override(self, instrument): instrument = INSTRUMENT_DICT[instrument] self.view.set_instrument_override(instrument) self.instrument = instrument def set_rb_num(self, rb_num): self.rb_num = rb_num def _validate(self): """ Ensure that the worker is ready to be started. :return: True if the worker can be started safely. """ if self.view.is_searching(): create_error_message( self.view, "Mantid is searching for data files. Please wait.") return False if not self.view.get_focus_valid(): create_error_message(self.view, "Check run numbers/path is valid.") return False if not self.view.get_vanadium_valid(): create_error_message(self.view, "Check vanadium run number/path is valid.") return False if not self.current_calibration.is_valid(): create_error_message( self.view, "Create or Load a calibration via the Calibration tab before focusing." ) return False if self.current_calibration.get_instrument() != self.instrument: create_error_message( self.view, "Please make sure the selected instrument matches instrument for the current calibration.\n" "The instrument for the current calibration is: " + self.current_calibration.get_instrument()) return False return True def _number_of_files_warning(self, paths): if len( paths ) > 10: # Just a guess on the warning for now. May change in future. response = QMessageBox.warning( self.view, 'Engineering Diffraction - Warning', 'You are attempting to focus {} workspaces. This may take some time.\n\n Would you like to continue?' .format(len(paths)), QMessageBox.Ok | QMessageBox.Cancel) return response == QMessageBox.Ok else: return True def _on_worker_error(self, error_info): logger.error(str(error_info)) self.emit_enable_button_signal() def set_focus_controls_enabled(self, enabled): self.view.set_focus_button_enabled(enabled) self.view.set_plot_output_enabled(enabled) def emit_enable_button_signal(self): self.view.sig_enable_controls.emit(True) def update_calibration(self, calibration): """ Update the current calibration following an call from a CalibrationNotifier :param calibration: The new current calibration. """ self.current_calibration = calibration region_text = calibration.get_roi_text() self.view.set_region_display_text(region_text)
class FocusPresenter(object): def __init__(self, model, view): self.model = model self.view = view self.worker = None self.calibration_observer = self.CalibrationObserver(self) # Connect view signals to local methods. self.view.set_on_focus_clicked(self.on_focus_clicked) self.view.set_enable_controls_connection(self.set_focus_controls_enabled) self.view.set_on_check_cropping_state_changed(self.show_cropping) # Variables from other GUI tabs. self.current_calibration = CalibrationInfo() self.instrument = "ENGINX" self.rb_num = None # Cropping Options self.cropping_widget = CroppingWidget(self.view, view=self.view.get_cropping_widget()) self.show_cropping(False) def on_focus_clicked(self): if not self._validate(): return banks, spectrum_numbers = self._get_banks() focus_paths = self.view.get_focus_filenames() if self._number_of_files_warning(focus_paths): self.start_focus_worker(focus_paths, banks, self.view.get_plot_output(), self.rb_num, spectrum_numbers) def start_focus_worker(self, focus_paths, banks, plot_output, rb_num, spectrum_numbers=None): """ Focus data in a separate thread to stop the main GUI from hanging. :param focus_paths: List of paths to the files containing the data to focus. :param banks: A list of banks that are to be focused. :param plot_output: True if the output should be plotted. :param rb_num: The RB Number from the main window (often an experiment id) :param spectrum_numbers: Optional parameter to crop to a specific list of spectrum numbers. """ self.worker = AsyncTask(self.model.focus_run, (focus_paths, banks, plot_output, self.instrument, rb_num, spectrum_numbers), error_cb=self._on_worker_error, finished_cb=self.emit_enable_button_signal) self.set_focus_controls_enabled(False) self.worker.start() def set_instrument_override(self, instrument): instrument = INSTRUMENT_DICT[instrument] self.view.set_instrument_override(instrument) self.instrument = instrument def set_rb_num(self, rb_num): self.rb_num = rb_num def _validate(self): """ Ensure that the worker is ready to be started. :return: True if the worker can be started safely. """ if self.view.is_searching(): create_error_message(self.view, "Mantid is searching for data files. Please wait.") return False if not self.view.get_focus_valid(): create_error_message(self.view, "Check run numbers/path is valid.") return False if not check_workspaces_exist() or not self.current_calibration.is_valid(): create_error_message( self.view, "Create or Load a calibration via the Calibration tab before focusing.") return False if self.current_calibration.get_instrument() != self.instrument: create_error_message( self.view, "Please make sure the selected instrument matches instrument for the current calibration.\n" "The instrument for the current calibration is: " + self.current_calibration.get_instrument()) return False if self.view.get_crop_checked() and not self.cropping_widget.is_valid(): create_error_message(self.view, "Check cropping values are valid.") return False return True def _number_of_files_warning(self, paths): if len(paths) > 10: # Just a guess on the warning for now. May change in future. response = QMessageBox.warning( self.view, 'Engineering Diffraction - Warning', 'You are attempting to focus {} workspaces. This may take some time.\n\n Would you like to continue?' .format(len(paths)), QMessageBox.Ok | QMessageBox.Cancel) return response == QMessageBox.Ok else: return True def _on_worker_error(self, _): self.emit_enable_button_signal() def set_focus_controls_enabled(self, enabled): self.view.set_focus_button_enabled(enabled) self.view.set_plot_output_enabled(enabled) def _get_banks(self): if self.view.get_crop_checked(): if self.cropping_widget.is_custom(): return None, self.cropping_widget.get_custom_spectra() else: return [self.cropping_widget.get_bank()], None else: return ["1", "2"], None def emit_enable_button_signal(self): self.view.sig_enable_controls.emit(True) def update_calibration(self, calibration): """ Update the current calibration following an call from a CalibrationNotifier :param calibration: The new current calibration. """ self.current_calibration = calibration def show_cropping(self, visible): self.view.set_cropping_widget_visibility(visible) # ----------------------- # Observers / Observables # ----------------------- class CalibrationObserver(Observer): def __init__(self, outer): Observer.__init__(self) self.outer = outer def update(self, observable, calibration): self.outer.update_calibration(calibration)