Esempio n. 1
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
Esempio n. 2
0
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())