From f62b07d9498f5c4af4cf3115f934168a6a0fea23 Mon Sep 17 00:00:00 2001 From: JoschD <26184899+JoschD@users.noreply.github.com> Date: Tue, 5 Dec 2023 18:16:31 +0100 Subject: [PATCH] buttons and selections working as expected --- .../segment_by_segment/main_controller.py | 110 +++++++++++++++--- omc3_gui/segment_by_segment/main_view.py | 19 ++- omc3_gui/utils/colors.py | 4 + omc3_gui/utils/threads.py | 29 +++-- omc3_gui/utils/widgets.py | 22 +++- 5 files changed, 139 insertions(+), 45 deletions(-) diff --git a/omc3_gui/segment_by_segment/main_controller.py b/omc3_gui/segment_by_segment/main_controller.py index 34118f3..9658a05 100644 --- a/omc3_gui/segment_by_segment/main_controller.py +++ b/omc3_gui/segment_by_segment/main_controller.py @@ -1,16 +1,16 @@ -from pathlib import Path -from typing import List, Sequence, Tuple, Union -from omc3_gui.segment_by_segment.segment_model import SegmentModel -from omc3_gui.utils.base_classes import Controller -from omc3_gui.utils.file_dialogs import OpenDirectoriesDialog, OpenDirectoryDialog -from omc3_gui.segment_by_segment.main_view import SbSWindow +import logging +from typing import Sequence + +from qtpy.QtCore import Slot + +from omc3_gui.segment_by_segment.defaults import DEFAULT_SEGMENTS from omc3_gui.segment_by_segment.main_model import SegmentTableModel, Settings -from qtpy.QtCore import Qt, Signal, Slot -from qtpy.QtWidgets import QFileDialog +from omc3_gui.segment_by_segment.main_view import SbSWindow from omc3_gui.segment_by_segment.measurement_model import OpticsMeasurement -import logging from omc3_gui.segment_by_segment.measurement_view import OpticsMeasurementDialog -from omc3_gui.segment_by_segment.defaults import DEFAULT_SEGMENTS +from omc3_gui.segment_by_segment.segment_model import SegmentModel +from omc3_gui.utils.base_classes import Controller +from omc3_gui.utils.file_dialogs import OpenDirectoriesDialog LOGGER = logging.getLogger(__name__) @@ -25,15 +25,15 @@ def __init__(self): self.settings = Settings() self._last_selected_optics_path = None + self.set_measurement_interaction_buttons_enabled(False) + self.set_all_segment_buttons_enabled(False) - def add_measurement(self, measurement: OpticsMeasurement): - self._view.get_measurement_list().add_item(measurement) - def connect_signals(self): self._view.button_load.clicked.connect(self.open_measurements) self._view.button_edit.clicked.connect(self.edit_measurement) self._view.button_remove.clicked.connect(self.remove_measurement) + self._view.button_run_segment.clicked.connect(self.run_segments) self._view.sig_list_optics_double_clicked.connect(self.edit_measurement) self._view.sig_list_optics_selected.connect(self.measurement_selection_changed) @@ -43,9 +43,22 @@ def connect_signals(self): self._view.button_default_segments.clicked.connect(self.add_default_segments) self._view.button_remove_segment.clicked.connect(self.remove_segment) - self._view.sig_table_segments_selected.connect(self.view_segment) + self._view.sig_table_segments_selected.connect(self.segment_selection_changed) # Measurements --- + def set_measurement_interaction_buttons_enabled(self, enabled: bool): + measurement_interaction_buttons = ( + self._view.button_remove, + self._view.button_edit, + self._view.button_matcher, + ) + for button in measurement_interaction_buttons: + button.setEnabled(enabled) + + + def add_measurement(self, measurement: OpticsMeasurement): + self._view.get_measurement_list().add_item(measurement) + @Slot() def open_measurements(self): LOGGER.debug("Opening new optics measurement. Asking for folder paths.") @@ -103,16 +116,27 @@ def remove_measurement(self, measurements: Sequence[OpticsMeasurement] = None): @Slot(tuple) def measurement_selection_changed(self, measurements: Sequence[OpticsMeasurement]): LOGGER.debug(f"Selected {len(measurements)} measurements.") + if not len(measurements): + self.set_measurement_interaction_buttons_enabled(False) + self._view.set_segments(SegmentTableModel()) + self.segment_selection_changed() + self.set_all_segment_buttons_enabled(False) + return + + self.set_measurement_interaction_buttons_enabled(True) + self.set_all_segment_buttons_enabled(True) + if len(measurements) > 1: self._view.button_edit.setEnabled(False) + self._view.set_segments(SegmentTableModel()) + self.segment_selection_changed() return - else: - self._view.button_edit.setEnabled(True) measurement = measurements[0] segment_model = SegmentTableModel() segment_model.add_items(measurement.segments) self._view.set_segments(segment_model) + self.segment_selection_changed() def get_single_measurement(self) -> OpticsMeasurement: measurements = self._view.get_selected_measurements() @@ -123,14 +147,42 @@ def get_single_measurement(self) -> OpticsMeasurement: return measurements[0] # Segments ----------------------------------------------------------------- + + def set_segment_interaction_buttons_enabled(self, enabled: bool = True): + segment_interaction_buttons = ( + self._view.button_run_segment, + self._view.button_copy_segment, + self._view.button_remove_segment, + ) + for button in segment_interaction_buttons: + button.setEnabled(enabled) + + def set_all_segment_buttons_enabled(self, enabled: bool = True): + segment_buttons = ( + self._view.button_run_segment, + self._view.button_copy_segment, + self._view.button_remove_segment, + self._view.button_new_segment, + self._view.button_default_segments, + self._view.button_load_segments, + ) + for button in segment_buttons: + button.setEnabled(enabled) + @Slot(tuple) - def view_segment(self, segments: Sequence[SegmentModel]): + def segment_selection_changed(self, segments: Sequence[SegmentModel] = None): + if segments is None: + segments = self._view.get_selected_segments() + LOGGER.debug(f"Showing {len(segments)} segments.") + if not len(segments): + self.set_segment_interaction_buttons_enabled(False) + return + + self.set_segment_interaction_buttons_enabled(True) if len(segments) > 1: LOGGER.debug("More than one segment selected. Clearing Plots.") return - - segment = segments[0] # Plot segements @Slot() @@ -212,3 +264,23 @@ def remove_segment(self, segments: Sequence[SegmentModel] = None): measurement.try_remove_segment(segment) self.measurement_selection_changed(selected_measurements) + + @Slot() + def run_segments(self, segments: Sequence[SegmentModel] = None): + if segments is None: + segments = self._view.get_selected_segments() + if not segments: + LOGGER.error("Please select at least one segment to run.") + return + + LOGGER.debug(f"Running {len(segments)} segments.") + selected_measurements = self._view.get_selected_measurements() + if not selected_measurements: + LOGGER.error("Please select at least one measurement.") + return + + for measurement in selected_measurements: + for segment in segments: + measurement.run_segment(segment) + + self.measurement_selection_changed(selected_measurements) diff --git a/omc3_gui/segment_by_segment/main_view.py b/omc3_gui/segment_by_segment/main_view.py index ab229c4..9b35fde 100644 --- a/omc3_gui/segment_by_segment/main_view.py +++ b/omc3_gui/segment_by_segment/main_view.py @@ -2,20 +2,19 @@ # from omc3_gui.segment_by_segment.segment_by_segment_ui import Ui_main_window import logging from typing import Dict, List, Sequence, Tuple -from PyQt5 import QtGui - -from qtpy import QtWidgets, QtGui -from qtpy.QtCore import Qt, Signal, Slot, QModelIndex, QItemSelection, QItemSelectionModel +from PyQt5 import QtGui +from qtpy import QtGui, QtWidgets +from qtpy.QtCore import QItemSelectionModel, QModelIndex, Qt, Signal, Slot from omc3_gui.plotting.classes import DualPlot from omc3_gui.segment_by_segment.main_model import MeasurementListModel, SegmentTableModel from omc3_gui.segment_by_segment.measurement_model import OpticsMeasurement from omc3_gui.segment_by_segment.segment_model import SegmentModel +from omc3_gui.utils import colors from omc3_gui.utils.base_classes import View from omc3_gui.utils.counter import HorizontalGridLayoutFiller from omc3_gui.utils.widgets import DefaultButton, EditButton, OpenButton, RemoveButton, RunButton -from omc3_gui.utils import colors LOGGER = logging.getLogger(__name__) @@ -68,7 +67,7 @@ def _connect_signals(self): self._list_view_measurements.selectionModel().selectionChanged.connect(self._handle_list_measurements_selected) # Segments --- - self._table_segments.selectionModel().selectionChanged.connect(self._handle_table_segments_selected) + # Set in set_segments, as this needs to be reset after each model setting. # Slots -------------------------------------------------------------------- @Slot(QModelIndex) @@ -80,17 +79,13 @@ def _handle_list_measurements_double_clicked(self, idx): def _handle_list_measurements_selected(self): LOGGER.debug("Optics List selection changed.") selected_measurements = self.get_selected_measurements() - if len(selected_measurements) == 0: - return self.sig_list_optics_selected.emit(selected_measurements) @Slot() def _handle_table_segments_selected(self): LOGGER.debug("Segment Table selection changed.") selected_segments = self.get_selected_segments() - if len(selected_segments) == 0: - return - self.sig_table_segment_selected.emit(selected_segments) + self.sig_table_segments_selected.emit(selected_segments) # GUI-Elements ------------------------------------------------------------- def _build_gui(self): @@ -228,6 +223,8 @@ def set_selected_measurements(self, indices: Sequence[QModelIndex] = ()): def set_segments(self, segment_model: SegmentTableModel): self._table_segments.setModel(segment_model) + self._table_segments.selectionModel().selectionChanged.connect(self._handle_table_segments_selected) + def get_segments(self) -> SegmentTableModel: return self._table_segments.model() diff --git a/omc3_gui/utils/colors.py b/omc3_gui/utils/colors.py index ec9e1f1..d4efafc 100644 --- a/omc3_gui/utils/colors.py +++ b/omc3_gui/utils/colors.py @@ -7,12 +7,16 @@ GREEN_DARK = "#28642A" GREEN_LIGHT = "#4CAF50" +GREEN_DARK_GREY = "#8EA18F" +GREEN_LIGHT_GREY = "#C8E6C9" RED_DARK = "#B71C1C" RED_LIGHT = "#F44336" +RED_GREY = "#CFADAD" BLUE_DARK = "#0D47A1" BLUE_LIGHT = "#2196F3" +BLUE_GREY = "#9FA8DA" # Machine Colors --- # LHC Colors diff --git a/omc3_gui/utils/threads.py b/omc3_gui/utils/threads.py index 31227a3..c16d0e4 100644 --- a/omc3_gui/utils/threads.py +++ b/omc3_gui/utils/threads.py @@ -1,15 +1,28 @@ +import logging +from qtpy.QtCore import QThread, Signal +from typing import Callable + +LOGGER = logging.getLogger(__name__) + + class BackgroundThread(QThread): on_exception = Signal([str]) - def __init__(self, view, function, message=None, - on_end_function=None, on_exception_function=None): + def __init__(self, + function: Callable, + message: str = None, + on_end_function: Callable = None, + on_exception_function: Callable = None): QThread.__init__(self) - self._view = view self._function = function self._message = message self._on_end_function = on_end_function self._on_exception_function = on_exception_function + + @property + def message(self): + return self._message def run(self): try: @@ -22,13 +35,11 @@ def start(self): self.finished.connect(self._on_end) self.on_exception.connect(self._on_exception) super(BackgroundThread, self).start() - self._view.show_background_task_dialog(self._message) def _on_end(self): - self._view.hide_background_task_dialog() - self._on_end_function() + if self._on_end_function: + self._on_end_function() def _on_exception(self, exception_message): - self._view.hide_background_task_dialog() - self._view.show_error_dialog("Error", exception_message) - self._on_exception_function(exception_message) \ No newline at end of file + if self._on_exception_function: + self._on_exception_function(exception_message) \ No newline at end of file diff --git a/omc3_gui/utils/widgets.py b/omc3_gui/utils/widgets.py index 310c70e..d869425 100644 --- a/omc3_gui/utils/widgets.py +++ b/omc3_gui/utils/widgets.py @@ -17,7 +17,10 @@ def __init__(self, *args, **kwargs): if not args and not "text" in kwargs: self.setText("Run") - self.setStyleSheet(f"background-color: {colors.GREEN_DARK}; color: {colors.TEXT_LIGHT};") + self.setStyleSheet( + f":enabled {{ background-color: {colors.GREEN_DARK}; color: {colors.TEXT_LIGHT}; }}" + f":disabled {{ background-color: {colors.GREEN_DARK_GREY}; color: {colors.GREYED_OUT_TEXT_DARK}; }}" + ) class OpenButton(QtWidgets.QPushButton): @@ -27,7 +30,10 @@ def __init__(self, *args, **kwargs): if not args and not "text" in kwargs: self.setText("Open") - self.setStyleSheet(f"background-color: {colors.GREEN_LIGHT}; color: {colors.TEXT_DARK};") + self.setStyleSheet( + f":enabled {{ background-color: {colors.GREEN_LIGHT}; color: {colors.TEXT_DARK}; }}" + f":disabled {{ background-color: {colors.GREEN_LIGHT_GREY}; color: {colors.GREYED_OUT_TEXT_DARK}; }}" + ) class RemoveButton(QtWidgets.QPushButton): @@ -36,10 +42,11 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if not args and not "text" in kwargs: self.setText("Remove") - - self.setStyleSheet(f"background-color: {colors.RED_LIGHT}; color: {colors.TEXT_DARK};") - + self.setStyleSheet( + f":enabled {{ background-color: {colors.RED_DARK}; color: {colors.TEXT_LIGHT}; }}" + f":disabled {{ background-color: {colors.RED_GREY}; color: {colors.GREYED_OUT_TEXT_DARK}; }}" + ) class EditButton(QtWidgets.QPushButton): @@ -48,7 +55,10 @@ def __init__(self, *args, **kwargs): if not args and not "text" in kwargs: self.setText("Edit") - self.setStyleSheet(f"background-color: {colors.BLUE_DARK}; color: {colors.TEXT_LIGHT};") + self.setStyleSheet( + f":enabled {{ background-color: {colors.BLUE_DARK}; color: {colors.TEXT_LIGHT}; }}" + f":disabled {{ background-color: {colors.BLUE_GREY}; color: {colors.GREYED_OUT_TEXT_DARK}; }}" + ) class DefaultButton(QtWidgets.QPushButton):