From 48111e5718082bf3bc6e903590689918bf1c8ed4 Mon Sep 17 00:00:00 2001 From: appleb_m Date: Fri, 26 Jun 2026 09:58:05 +0200 Subject: [PATCH] gui: always allow pausing automation; only gate starting/resuming The play/pause toggle ran its start-time checks (beamline state, busy, baton, maintenance) before the pause branch, so when running you could be blocked from pausing if the beamline was in the wrong state or busy. Handle the pause toggle first and return immediately (unconditional), and run the start-condition gates only when starting/resuming from paused. Co-Authored-By: Claude Opus 4.8 --- src/aare/gui/panels/sample_queue_panel.py | 146 +++++++++++----------- 1 file changed, 76 insertions(+), 70 deletions(-) diff --git a/src/aare/gui/panels/sample_queue_panel.py b/src/aare/gui/panels/sample_queue_panel.py index ce46a850..629c4cc5 100644 --- a/src/aare/gui/panels/sample_queue_panel.py +++ b/src/aare/gui/panels/sample_queue_panel.py @@ -268,6 +268,20 @@ class SampleQueuePanel(QFrame): def run(self): self.__recovery_timer.stop() + + # Pausing must ALWAYS be possible, regardless of beamline state, busy + # flag, baton or maintenance. Only starting/resuming is gated on + # conditions, so handle the pause toggle first and return immediately. + if not self.__pause: + self.__set_to_pause = True + self.__pause = True + self.table_model.set_running(False) + self.play_button.setText("▶ Run") + self._emit_samples_in_queue_changed() + self.automation_running_changed.emit(False) + return + + # --- Starting/resuming: require the beamline to be in a good state. --- checks_enabled = self._checks_enabled() if checks_enabled: if self.__warning_msg_box: @@ -282,82 +296,74 @@ class SampleQueuePanel(QFrame): ) return - if self.__pause: - if self.__busy: - logger.error(f"Cannot run automation while beamline is busy. Busy flag = {self.__busy}") - self.show_error_dialog( - title="Beamline is busy", - msg="Cannot run automation while beamline is busy", - info="Please wait until beamline is idle " - "or contact your local contact for support", - ) - return + if self.__busy: + logger.error(f"Cannot run automation while beamline is busy. Busy flag = {self.__busy}") + self.show_error_dialog( + title="Beamline is busy", + msg="Cannot run automation while beamline is busy", + info="Please wait until beamline is idle " + "or contact your local contact for support", + ) + return - if self.__baton_holder is SessionsStateEnum.Vacant: - self.show_error_dialog( - title="Session is vacant", - msg="Starting automation while session is vacant is not currently implemented", - info="Please grab the baton before continuing " - "or contact your local contact for support", - ) - return + if self.__baton_holder is SessionsStateEnum.Vacant: + self.show_error_dialog( + title="Session is vacant", + msg="Starting automation while session is vacant is not currently implemented", + info="Please grab the baton before continuing " + "or contact your local contact for support", + ) + return - elif self.__baton_holder is not SessionsStateEnum.OwnedByYou: - self.show_error_dialog( - title="You do not hold the baton", - msg="You do not hold the baton.", - info="Please request the baton if it is your shift." - "If your baton request is denied and it should be the start of your shift," - "please contact your local contact for support", - ) - return + elif self.__baton_holder is not SessionsStateEnum.OwnedByYou: + self.show_error_dialog( + title="You do not hold the baton", + msg="You do not hold the baton.", + info="Please request the baton if it is your shift." + "If your baton request is denied and it should be the start of your shift," + "please contact your local contact for support", + ) + return - if self.__beamline_state is BeamlineStateEnum.Maintenance: - self.show_error_dialog( - title="Maintenance mode", - msg="Cannot run automation while beamline is in maintenance mode", - info=("Change to safe state such as Sample Exchange before trying to continue. " - "If this issue persists please contact your local contact for support."), - ) - return + if self.__beamline_state is BeamlineStateEnum.Maintenance: + self.show_error_dialog( + title="Maintenance mode", + msg="Cannot run automation while beamline is in maintenance mode", + info=("Change to safe state such as Sample Exchange before trying to continue. " + "If this issue persists please contact your local contact for support."), + ) + return - if len(self.table_model.samples) > 0: - if checks_enabled: - bad = self._bad_conditions() - if bad: - logger.warning(f"Cannot start automation; beamline not ready: {bad}") - self.show_error_dialog( - title="Beamline not ready", - msg="Cannot start automation:\n- " + "\n- ".join(bad), - info="Fix the above, or untick 'Pause on bad conditions' for testing.", - ) - return + if len(self.table_model.samples) > 0: + if checks_enabled: + bad = self._bad_conditions() + if bad: + logger.warning(f"Cannot start automation; beamline not ready: {bad}") + self.show_error_dialog( + title="Beamline not ready", + msg="Cannot start automation:\n- " + "\n- ".join(bad), + info="Fix the above, or untick 'Pause on bad conditions' for testing.", + ) + return - self.table_model.set_running(True) - self.__set_to_pause = False - self.__pause = False - self.play_button.setText("⏸ Pause") - current = self.table_model.samples[0] - self._current_db_id = current.db_id - self._emit_samples_in_queue_changed() - self.automation_running_changed.emit(True) - self.auto_scan.emit(current) - self.viewer_track_online.emit() - else: - logger.debug("No samples in queue, skipping") - self.show_error_dialog( - title="No Samples in Queue", - msg="Cannot run automation as there are no samples in the queue.", - info="Please add samples to the queue.", - ) - return - else: - self.__set_to_pause = True - self.__pause = True - self.table_model.set_running(False) - self.play_button.setText("▶ Run") + self.table_model.set_running(True) + self.__set_to_pause = False + self.__pause = False + self.play_button.setText("⏸ Pause") + current = self.table_model.samples[0] + self._current_db_id = current.db_id self._emit_samples_in_queue_changed() - self.automation_running_changed.emit(False) + self.automation_running_changed.emit(True) + self.auto_scan.emit(current) + self.viewer_track_online.emit() + else: + logger.debug("No samples in queue, skipping") + self.show_error_dialog( + title="No Samples in Queue", + msg="Cannot run automation as there are no samples in the queue.", + info="Please add samples to the queue.", + ) + return def clear(self): self.table_model.clearSamples()