Beispiel #1
0
    def __init__(self, recoil_element: RecoilElement, colormap,
                 element_simulation: ElementSimulation):
        """Inits a recoil info dialog.

        Args:
            recoil_element: A RecoilElement object.
            colormap: Colormap for elements.
            element_simulation: Element simulation that has the recoil element.
        """
        super().__init__()
        self.recoil_element = recoil_element
        self.element_simulation = element_simulation

        self.tmp_color = QColor(self.recoil_element.color)
        self.colormap = colormap

        value = self.recoil_element.reference_density
        self.scientific_spinbox = ScientificSpinBox(value=value,
                                                    minimum=0.01,
                                                    maximum=9.99e23)

        uic.loadUi(gutils.get_ui_dir() / "ui_recoil_info_dialog.ui", self)

        self.okPushButton.clicked.connect(self.__accept_settings)
        self.cancelPushButton.clicked.connect(self.close)
        self.colorPushButton.clicked.connect(self.__change_color)

        self.fields_are_valid = True
        iv.set_input_field_red(self.nameLineEdit)
        self.nameLineEdit.textChanged.connect(
            lambda: iv.check_text(self.nameLineEdit, qwidget=self))
        self.nameLineEdit.textEdited.connect(self.__validate)

        self.name = recoil_element.name
        self.description = recoil_element.description
        self.formLayout.insertRow(
            4, QtWidgets.QLabel(r"Reference density [at./cm<sup>3</sup>]:"),
            self.scientific_spinbox)
        self.formLayout.removeRow(self.widget)

        self.description = recoil_element.description
        self.isOk = False

        self.dateLabel.setText(
            time.strftime(
                "%c %z %Z",
                time.localtime(self.recoil_element.modification_time)))

        title = f"Recoil element: " \
                f"{self.recoil_element.element.get_prefix()}"

        self.infoGroupBox.setTitle(title)

        self.__set_color_button_color(self.recoil_element.element.symbol)

        self.exec_()
    def setUp(self):
        self.minimum = 1.0e20
        self.maximum = 9.9e23
        self.sbox = ScientificSpinBox(1.123e+22,
                                      minimum=self.minimum,
                                      maximum=self.maximum)

        down_btn = self.sbox.downButton
        up_btn = self.sbox.upButton
        self.click_down = lambda: QTest.mouseClick(down_btn, Qt.LeftButton)
        self.click_up = lambda: QTest.mouseClick(up_btn, Qt.LeftButton)
Beispiel #3
0
    def __init__(self):
        super().__init__()
        self.spinbox = QtWidgets.QSpinBox()
        self.doubleSpinbox = QtWidgets.QDoubleSpinBox()
        self.textBox = QtWidgets.QTextEdit()
        self.timeEdit = QtWidgets.QTimeEdit()
        self.checkBox = QtWidgets.QCheckBox()
        self.label = QtWidgets.QLabel()
        self.plaintext = QtWidgets.QPlainTextEdit()
        self.not2waySpinBox = QtWidgets.QSpinBox()
        self.scibox = ScientificSpinBox()
        self.listWidget = QtWidgets.QListWidget()
        self.group_box = QtWidgets.QGroupBox()

        self.radio_group = QtWidgets.QButtonGroup()
        for i in range(3):
            btn = QtWidgets.QRadioButton(f"rb{i}", self)
            self.radio_group.addButton(btn)

        gutils.set_btn_group_data(self.radio_group,
                                  ["fizz", "buzz", "fizzbuzz"])

        self.comboBox = QtWidgets.QComboBox()
        for i in range(3):
            self.comboBox.addItem(f"x-{i + 42}", i)

        self.tree = QtWidgets.QTreeWidget()
        gutils.fill_tree(self.tree.invisibleRootItem(), ["foo", "bar", "baz"])
Beispiel #4
0
    def __init__(self, **kwargs):
        """Initialize the widget.

        Args:
            kwargs: property values to be shown in the widget.
        """
        ui_file = gutils.get_ui_dir() / "ui_optimization_fluence_params.ui"
        self.fluenceDoubleSpinBox = ScientificSpinBox(10e12)
        super().__init__(ui_file, **kwargs)
        self.fluence_form_layout.addRow("Upper limit",
                                        self.fluenceDoubleSpinBox)
Beispiel #5
0
class RecoilInfoDialog(QtWidgets.QDialog,
                       bnd.PropertyBindingWidget,
                       metaclass=gutils.QtABCMeta):
    """Dialog for editing the name, description and reference density
    of a recoil element.
    """
    # TODO possibly track name changes
    name = bnd.bind("nameLineEdit")
    description = bnd.bind("descriptionLineEdit")
    reference_density = bnd.bind("scientific_spinbox")

    @property
    def color(self):
        return self.tmp_color.name()

    def __init__(self, recoil_element: RecoilElement, colormap,
                 element_simulation: ElementSimulation):
        """Inits a recoil info dialog.

        Args:
            recoil_element: A RecoilElement object.
            colormap: Colormap for elements.
            element_simulation: Element simulation that has the recoil element.
        """
        super().__init__()
        self.recoil_element = recoil_element
        self.element_simulation = element_simulation

        self.tmp_color = QColor(self.recoil_element.color)
        self.colormap = colormap

        value = self.recoil_element.reference_density
        self.scientific_spinbox = ScientificSpinBox(value=value,
                                                    minimum=0.01,
                                                    maximum=9.99e23)

        uic.loadUi(gutils.get_ui_dir() / "ui_recoil_info_dialog.ui", self)

        self.okPushButton.clicked.connect(self.__accept_settings)
        self.cancelPushButton.clicked.connect(self.close)
        self.colorPushButton.clicked.connect(self.__change_color)

        self.fields_are_valid = True
        iv.set_input_field_red(self.nameLineEdit)
        self.nameLineEdit.textChanged.connect(
            lambda: iv.check_text(self.nameLineEdit, qwidget=self))
        self.nameLineEdit.textEdited.connect(self.__validate)

        self.name = recoil_element.name
        self.description = recoil_element.description
        self.formLayout.insertRow(
            4, QtWidgets.QLabel(r"Reference density [at./cm<sup>3</sup>]:"),
            self.scientific_spinbox)
        self.formLayout.removeRow(self.widget)

        self.description = recoil_element.description
        self.isOk = False

        self.dateLabel.setText(
            time.strftime(
                "%c %z %Z",
                time.localtime(self.recoil_element.modification_time)))

        title = f"Recoil element: " \
                f"{self.recoil_element.element.get_prefix()}"

        self.infoGroupBox.setTitle(title)

        self.__set_color_button_color(self.recoil_element.element.symbol)

        self.exec_()

    def __density_valid(self):
        """
        Check if density value is valid and in limits.

        Return:
            True or False.
        """
        try:
            self.scientific_spinbox.get_value()
            return True
        except TypeError:
            return False

    def __accept_settings(self):
        """Function for accepting the current settings and closing the dialog
        window.
        """
        if not self.fields_are_valid or not self.__density_valid():
            QtWidgets.QMessageBox.critical(
                self, "Warning", "Some of the setting values are invalid.\n"
                "Please input values in fields indicated in red.",
                QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.Ok)
            return

        if self.name != self.recoil_element.name:
            # Check that the new name is not already in use
            if self.name in (
                    r.name for r in  # has_recoil
                    self.element_simulation.recoil_elements):
                QtWidgets.QMessageBox.critical(
                    self, "Warning",
                    "Name of the recoil element is already in use. Please use "
                    "a different name", QtWidgets.QMessageBox.Ok,
                    QtWidgets.QMessageBox.Ok)
                return

        # If current recoil is used in a running simulation
        if self.recoil_element is \
                self.element_simulation.get_main_recoil():
            if (self.element_simulation.is_simulation_running() or
                    self.element_simulation.is_optimization_running()) and \
                    self.name != self.recoil_element.name:
                reply = QtWidgets.QMessageBox.question(
                    self, "Recoil used in simulation",
                    "This recoil is used in a simulation that is "
                    "currently running.\nIf you change the name of "
                    "the recoil, the running simulation will be "
                    "stopped.\n\n"
                    "Do you want to save changes anyway?",
                    QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No
                    | QtWidgets.QMessageBox.Cancel,
                    QtWidgets.QMessageBox.Cancel)
                if reply == QtWidgets.QMessageBox.No or reply == \
                        QtWidgets.QMessageBox.Cancel:
                    return
                else:
                    self.element_simulation.stop()

        self.isOk = True
        self.close()

    def __change_color(self):
        """
        Change the color of the recoil element.
        """
        dialog = QtWidgets.QColorDialog(self)
        color = dialog.getColor(self.tmp_color)
        if color.isValid():
            self.tmp_color = color
            self.__change_color_button_color(
                self.recoil_element.element.symbol)

    def __change_color_button_color(self, element: str):
        """
        Change color button's color.

        Args:
            element: String representing element name.
        """
        df.set_btn_color(self.colorPushButton, self.tmp_color, self.colormap,
                         element)

    def __set_color_button_color(self, element):
        """Set default color of element to color button.

        Args:
            element: String representing element.
        """
        self.colorPushButton.setEnabled(True)
        self.tmp_color = QColor(self.recoil_element.color)
        self.__change_color_button_color(element)

    def __validate(self):
        """
        Validate the recoil name.
        """
        text = self.name
        regex = "^[A-Za-z0-9-ÖöÄäÅå]*"
        valid_text = iv.validate_text_input(text, regex)

        self.name = valid_text
Beispiel #6
0
    def __init__(self, obj: Union[Measurement, Simulation], preset_folder=None):
        """Initializes the widget.

        Args:
            obj: object that uses these settings, either a Measurement or a
                Simulation.
        """
        super().__init__()
        uic.loadUi(gutils.get_ui_dir() / "ui_measurement_settings_tab.ui", self)
        self.fluenceDoubleSpinBox = ScientificSpinBox()
        image = gf.get_root_dir() / "images" / "measurement_setup_angles.png"
        pixmap = QtGui.QPixmap(str(image))
        self.picture.setScaledContents(True)
        self.picture.setPixmap(pixmap)

        self.obj = obj
        self.__original_property_values = {}

        locale = QLocale.c()

        self.energyDoubleSpinBox.setLocale(locale)
        self.energyDistDoubleSpinBox.setLocale(locale)
        self.spotSizeXdoubleSpinBox.setLocale(locale)
        self.spotSizeYdoubleSpinBox.setLocale(locale)
        self.divergenceDoubleSpinBox.setLocale(locale)
        self.currentDoubleSpinBox.setLocale(locale)
        self.timeDoubleSpinBox.setLocale(locale)
        self.runChargeDoubleSpinBox.setLocale(locale)

        self.targetThetaDoubleSpinBox.setLocale(locale)
        self.detectorThetaDoubleSpinBox.setLocale(locale)
        self.detectorFiiDoubleSpinBox.setLocale(locale)
        self.targetFiiDoubleSpinBox.setLocale(locale)

        # Fii angles are currently not used so disable their spin boxes
        self.detectorFiiDoubleSpinBox.setEnabled(False)
        self.targetFiiDoubleSpinBox.setEnabled(False)
        gutils.fill_combobox(self.profileComboBox, Profile)

        # Copy of measurement's/simulation's run or default run
        # TODO should default run also be copied?
        if not self.obj.run:
            self.tmp_run = self.obj.request.default_run
        else:
            self.tmp_run = copy.deepcopy(self.obj.run)

        self.isotopeInfoLabel.setVisible(False)

        self.beamIonButton.clicked.connect(self.change_element)

        self.fields_are_valid = False
        iv.set_input_field_red(self.nameLineEdit)
        self.nameLineEdit.textChanged.connect(
            lambda: iv.check_text(self.nameLineEdit, qwidget=self))
        self.nameLineEdit.textEdited.connect(self.__validate)
        self.nameLineEdit.setEnabled(False)

        self.run_form_layout: QtWidgets.QFormLayout
        self.run_form_layout.insertRow(3, "Fluence", self.fluenceDoubleSpinBox)
        self.fluenceDoubleSpinBox.scientificLineEdit.setContextMenuPolicy(
            Qt.ActionsContextMenu)
        self.actionMultiply = QtWidgets.QAction(
            self.fluenceDoubleSpinBox.scientificLineEdit)
        self.actionMultiply.triggered.connect(self.__multiply_fluence)
        self.fluenceDoubleSpinBox.scientificLineEdit.addAction(
            self.actionMultiply)

        self.actionUndo = QtWidgets.QAction(
            self.fluenceDoubleSpinBox.scientificLineEdit)
        self.actionUndo.setText("Undo multiply")
        self.actionUndo.triggered.connect(self.__undo_fluence)

        self.actionUndo.setEnabled(bool(self.tmp_run.previous_fluence))
        self.fluenceDoubleSpinBox.scientificLineEdit.addAction(self.actionUndo)

        self.clipboard = QGuiApplication.clipboard()
        self._ratio = None
        self.clipboard.changed.connect(self.__update_multiply_action)
        self.__update_multiply_action()

        self.energyDoubleSpinBox.setToolTip("Energy set in MeV with.")

        if preset_folder is not None:
            self.preset_widget = PresetWidget.add_preset_widget(
                preset_folder / "measurement", "mea",
                lambda w: self.layout().insertWidget(0, w),
                save_callback=self.save_properties_to_file,
                load_callback=self.load_properties_from_file
            )
        else:
            self.preset_widget = None

        self.show_settings()
Beispiel #7
0
    def __init__(self,
                 obj: Detector,
                 request: Request,
                 icon_manager,
                 run=None):
        """Initializes a DetectorSettingsWidget object.

        Args:
              obj: a Detector object.
              request: Which request it belongs to.
              icon_manager: IconManager object.
              run: Run object. None if detector is default detector.
        """
        super().__init__()
        uic.loadUi(gutils.get_ui_dir() / "ui_request_detector_settings.ui",
                   self)

        self.obj = obj
        self.request = request
        self.icon_manager = icon_manager
        self.run = run
        self.__original_properties = {}

        # Temporary foils list which holds all the information given in the
        # foil dialog
        # If user presses ok or apply, these values will be saved into
        # request's default detector
        self.tmp_foil_info = []

        # List of foil indexes that are timing foils
        self.tof_foils = []

        # Add foil widgets and foil objects
        self.detector_structure_widgets = []
        self.foils_layout = self._add_default_foils(self.obj)
        self.detectorScrollAreaContents.layout().addLayout(self.foils_layout)
        self.newFoilButton.clicked.connect(
            lambda: self._add_new_foil(self.foils_layout))

        self.addEfficiencyButton.clicked.connect(self.__add_efficiency)
        self.removeEfficiencyButton.clicked.connect(self.__remove_efficiency)
        self.plotEfficiencyButton.clicked.connect(self.__plot_efficiency)

        self.efficiencyListWidget.itemSelectionChanged.connect(
            self._enable_remove_btn)
        self._enable_remove_btn()

        # Calibration settings
        # TODO: Require saving affected cuts if beam setting has been changed
        self.executeCalibrationButton.clicked.connect(
            self.__open_calibration_dialog)
        self.executeCalibrationButton.setEnabled(
            not self.request.samples.measurements.is_empty())

        gutils.fill_combobox(self.typeComboBox, DetectorType)

        self.fields_are_valid = False
        iv.set_input_field_red(self.nameLineEdit)
        self.nameLineEdit.textChanged.connect(
            lambda: iv.check_text(self.nameLineEdit, qwidget=self))
        self.nameLineEdit.textEdited.connect(
            lambda: iv.sanitize_file_name(self.nameLineEdit))
        self.nameLineEdit.setEnabled(False)

        locale = QLocale.c()
        self.timeResSpinBox.setLocale(locale)
        self.virtualSizeXSpinBox.setLocale(locale)
        self.virtualSizeYSpinBox.setLocale(locale)
        self.angleSlopeLineEdit.setLocale(locale)
        self.angleOffsetLineEdit.setLocale(locale)

        # Create scientific spinboxes for tof slope and tof offset
        self.formLayout_2.removeRow(self.slopeLineEdit)
        self.formLayout_2.removeRow(self.offsetLineEdit)

        self.scientific_tof_slope = ScientificSpinBox(minimum=-math.inf,
                                                      maximum=math.inf)
        self.scientific_tof_offset = ScientificSpinBox(minimum=-math.inf,
                                                       maximum=math.inf)

        self.formLayout_2.insertRow(0, "ToF slope [s/channel]:",
                                    self.scientific_tof_slope)
        self.formLayout_2.insertRow(1, "ToF offset[s]:",
                                    self.scientific_tof_offset)

        if platform.system() == "Darwin":
            self.scientific_tof_offset.scientificLineEdit.setFixedWidth(170)
            self.scientific_tof_slope.scientificLineEdit.setFixedWidth(170)

        # Save as and load
        self.saveButton.clicked.connect(self.__save_file)
        self.loadButton.clicked.connect(self.__load_file)

        self.show_settings()
class TestSciSpinbox(unittest.TestCase):
    def setUp(self):
        self.minimum = 1.0e20
        self.maximum = 9.9e23
        self.sbox = ScientificSpinBox(1.123e+22,
                                      minimum=self.minimum,
                                      maximum=self.maximum)

        down_btn = self.sbox.downButton
        up_btn = self.sbox.upButton
        self.click_down = lambda: QTest.mouseClick(down_btn, Qt.LeftButton)
        self.click_up = lambda: QTest.mouseClick(up_btn, Qt.LeftButton)

    def test_display(self):
        self.sbox.minimum = -math.inf

        self.sbox.set_value(5.5e+22)
        self.assertEqual("5.5e+22", self.sbox.scientificLineEdit.text())

        self.sbox.set_value(math.pi * 1e20)
        self.assertEqual("3.1415926535897e+20",
                         self.sbox.scientificLineEdit.text())

        self.sbox.set_value(1.00000e21)
        self.assertEqual("1.0e+21", self.sbox.scientificLineEdit.text())

        self.sbox.set_value(1.00000e-21)
        self.assertEqual("1.0e-21", self.sbox.scientificLineEdit.text())

        self.sbox.set_value(-1.00000e-21)
        self.assertEqual("-1.0e-21", self.sbox.scientificLineEdit.text())

        self.sbox.set_value(0.1)
        self.assertEqual("1.0e-1", self.sbox.scientificLineEdit.text())

        self.sbox.set_value(0)
        self.assertEqual("0.0e+0", self.sbox.scientificLineEdit.text())

    def test_typed_values(self):
        self.sbox.scientificLineEdit.setText("1.321e20")
        self.assertEqual(1.321e20, self.sbox.get_value())

        self.sbox.scientificLineEdit.setText("0")
        self.assertEqual(0, self.sbox.get_value())

        self.sbox.scientificLineEdit.setText("foo")
        self.assertRaises(TypeError, lambda: self.sbox.get_value())

    def test_decrease(self):
        self.sbox.minimum = -math.inf
        self.sbox.set_value(5.5e+22)
        self.click_down()
        self.assertEqual(5.4e+22, self.sbox.get_value())

        self.sbox.set_value(1.0001e+22)
        self.click_down()
        self.assertEqual(9.9001e+21, self.sbox.get_value())

        self.sbox.set_value(0.0e0)
        self.click_down()
        self.assertEqual(-1.0e-2, self.sbox.get_value())

        self.sbox.set_value(1.05e-3)
        self.click_down()
        self.assertEqual(9.95e-4, self.sbox.get_value())

        self.sbox.set_value(-9.95e-4)
        self.click_down()
        self.assertEqual(-1.05e-3, self.sbox.get_value())

        self.sbox.scientificLineEdit.setText("foo")
        self.click_down()
        self.assertEqual("foo", self.sbox.scientificLineEdit.text())

    def test_increase(self):
        self.sbox.minimum = -math.inf
        self.sbox.set_value(9.81e+22)
        self.click_up()
        self.assertEqual(9.91e+22, self.sbox.get_value())

        self.click_up()
        self.assertEqual(1.01e+23, self.sbox.get_value())

        self.sbox.set_value(0.0e0)
        self.click_up()
        self.assertEqual(1.0e-2, self.sbox.get_value())

        self.sbox.set_value(9.9e0)
        self.click_up()
        self.assertEqual(1.0e1, self.sbox.get_value())

        self.sbox.set_value(-1.05e-10)
        self.click_up()
        self.assertEqual(-9.95e-11, self.sbox.get_value())

    def test_set_value(self):
        self.sbox.set_value(5e22)
        self.assertEqual(5e22, self.sbox.get_value())

        # Value below min
        self.sbox.set_value(10)
        self.assertEqual(self.minimum, self.sbox.get_value())

        # Value over max
        self.sbox.set_value(5e25)
        self.assertEqual(self.maximum, self.sbox.get_value())

        # Try setting a string
        self.sbox.set_value("5e21")
        self.assertEqual(5e21, self.sbox.get_value())

    def test_value_properties(self):
        # After n up clicks and n down clicks, value of the spinbox should
        # be the same as it was when started
        self.sbox.minimum = -math.inf
        self.sbox.maximum = math.inf
        value_min = -10.0e-10
        value_max = 10.0e-10
        max_clicks = 25
        n = 15

        for i in range(n):
            value = random.uniform(value_min, value_max)
            self.sbox.set_value(value)
            x0 = self.sbox.get_value()
            clicks = random.randint(1, max_clicks)
            click_order = [
                *[self.click_down] * clicks, *[self.click_up] * clicks
            ]
            random.shuffle(click_order)

            for cl in click_order:
                x1 = self.sbox.get_value()
                cl()
                x2 = self.sbox.get_value()
                if cl is self.click_down:
                    self.assertLess(x2, x1)
                else:
                    self.assertLess(x1, x2)

            self.assertEqual(x0, self.sbox.get_value())