def test_unit_validator_with_metres_set_as_expected_dimensionality(): validator = UnitValidator(expected_dimensionality=METRES) lengths = ["mile", "cm", "centimetre", "yard", "km"] not_lengths = [ "minute", "hour", "ounce", "stone", "pound", "amp", "abc", "c", "3.0", "123", "", "`?@#", "}", "2 metres", ] for unit in lengths: assert validator.validate(unit, 0) == QValidator.Acceptable for unit in not_lengths: assert validator.validate(unit, 0) == QValidator.Intermediate
def test_unit_validator(): validator = UnitValidator() lengths = ["mile", "cm", "centimetre", "yard", "km"] not_lengths = [ "minute", "hour", "ounce", "stone", "pound", "amp", "abc", "c", "3.0", "123", "", "`?@#", "}", "2 metres", ] for unit in lengths: assert validator.validate(unit, 0) == QValidator.Acceptable for unit in not_lengths: assert validator.validate(unit, 0) == QValidator.Intermediate
def test_unit_validator_with_no_expected_dimensionality(): validator = UnitValidator() valid_units = ["deg", "m", "cm", "dm", "rad"] invalid_units = ["asdfghj", "degre", "2 degrees"] for unit in valid_units: assert validator.validate(unit, 0) == QValidator.Acceptable for unit in invalid_units: assert validator.validate(unit, 0) == QValidator.Intermediate
def setupUi(self, parent_dialog, pixel_options: PixelOptions = PixelOptions()): """ Sets up push buttons and validators for the add component window. """ super().setupUi(parent_dialog) # Connect the button calls with functions self.ok_button.clicked.connect(self.on_ok) # Disable by default as component name will be missing at the very least. self.ok_button.setEnabled(False) # Set default URL to nexus base classes in web view #self.webEngineView.setUrl( # QUrl( # "http://download.nexusformat.org/doc/html/classes/base_classes/index.html" # ) #) self.meshRadioButton.clicked.connect(self.show_mesh_fields) self.CylinderRadioButton.clicked.connect(self.show_cylinder_fields) self.noShapeRadioButton.clicked.connect(self.show_no_geometry_fields) self.fileBrowseButton.clicked.connect(self.mesh_file_picker) self.fileLineEdit.setValidator(GeometryFileValidator(GEOMETRY_FILE_TYPES)) self.fileLineEdit.validator().is_valid.connect( partial(validate_line_edit, self.fileLineEdit) ) self.fileLineEdit.textChanged.connect(self.populate_pixel_mapping_if_necessary) self.componentTypeComboBox.currentIndexChanged.connect(self.on_nx_class_changed) # Set default geometry type and show the related fields. self.noShapeRadioButton.setChecked(True) self.show_no_geometry_fields() component_list = self.instrument.get_component_list().copy() if self.component_to_edit: for item in component_list: if item.name == self.component_to_edit.name: component_list.remove(item) name_validator = NameValidator(component_list) self.nameLineEdit.setValidator(name_validator) self.nameLineEdit.validator().is_valid.connect( partial( validate_line_edit, self.nameLineEdit, tooltip_on_accept="Component name is valid.", tooltip_on_reject=f"Component name is not valid. Suggestion: ", suggestion_callable=self.generate_name_suggestion, ) ) validate_line_edit(self.fileLineEdit, False) self.unitsLineEdit.setValidator(UnitValidator()) self.unitsLineEdit.validator().is_valid.connect( partial( validate_line_edit, self.unitsLineEdit, tooltip_on_reject="Units not valid", tooltip_on_accept="Units Valid", ) ) self.componentTypeComboBox.addItems(list(self.nx_component_classes.keys())) self.componentTypeComboBox.currentIndexChanged.connect( self.change_pixel_options_visibility ) # Set whatever the default nx_class is so the fields autocompleter can use the possible fields in the nx_class self.on_nx_class_changed() self.fieldsListWidget.itemClicked.connect(self.select_field) self.pixel_options = pixel_options self.pixel_options.setupUi(self.pixelOptionsWidget) self.pixelOptionsWidget.ui = self.pixel_options if self.component_to_edit: parent_dialog.setWindowTitle( f"Edit Component: {get_name_of_node(self.component_to_edit.group)}" ) self.ok_button.setText("Edit Component") self._fill_existing_entries() if self.get_pixel_visibility_condition(): self.pixel_options.fill_existing_entries(self.component_to_edit) self.ok_validator = OkValidator( self.noShapeRadioButton, self.meshRadioButton, self.pixel_options.validator ) self.ok_validator.is_valid.connect(self.ok_button.setEnabled) self.nameLineEdit.validator().is_valid.connect(self.ok_validator.set_name_valid) [ button.clicked.connect(self.ok_validator.validate_ok) for button in [ self.meshRadioButton, self.CylinderRadioButton, self.noShapeRadioButton, ] ] self.unitsLineEdit.validator().is_valid.connect( self.ok_validator.set_units_valid ) self.fileLineEdit.validator().is_valid.connect(self.ok_validator.set_file_valid) self.fileLineEdit.validator().is_valid.connect(self.set_file_valid) # Validate the default values set by the UI self.unitsLineEdit.validator().validate(self.unitsLineEdit.text(), 0) self.nameLineEdit.validator().validate(self.nameLineEdit.text(), 0) self.fileLineEdit.validator().validate(self.fileLineEdit.text(), 0) self.addFieldPushButton.clicked.connect(self.add_field) self.removeFieldPushButton.clicked.connect(self.remove_field) # Connect the pixel mapping press signal the populate pixel mapping method self.pixel_options.pixel_mapping_button_pressed.connect( self.populate_pixel_mapping_if_necessary ) self.cylinderCountSpinBox.valueChanged.connect( self.populate_pixel_mapping_if_necessary ) self.meshRadioButton.clicked.connect(self.set_pixel_related_changes) self.CylinderRadioButton.clicked.connect(self.set_pixel_related_changes) self.noShapeRadioButton.clicked.connect(self.set_pixel_related_changes) self.change_pixel_options_visibility()
def __init__( self, possible_field_names=None, parent: QListWidget = None, instrument: "Instrument" = None, # noqa: F821 hide_name_field: bool = False, ): super(FieldWidget, self).__init__(parent) if possible_field_names is None: possible_field_names = [] self.edit_dialog = QDialog(parent=self) self.attrs_dialog = FieldAttrsDialog(parent=self) self.instrument = instrument self.field_name_edit = FieldNameLineEdit(possible_field_names) self.hide_name_field = hide_name_field if hide_name_field: self.name = str(uuid.uuid4()) self.units_line_edit = QLineEdit() self.unit_validator = UnitValidator() self.units_line_edit.setValidator(self.unit_validator) self.unit_validator.is_valid.connect( partial(validate_line_edit, self.units_line_edit)) self.units_line_edit.setPlaceholderText(CommonAttrs.UNITS) self.field_type_combo = QComboBox() self.field_type_combo.addItems([item.value for item in FieldType]) self.field_type_combo.currentIndexChanged.connect( self.field_type_changed) fix_horizontal_size = QSizePolicy() fix_horizontal_size.setHorizontalPolicy(QSizePolicy.Fixed) self.field_type_combo.setSizePolicy(fix_horizontal_size) self.value_type_combo = QComboBox() self.value_type_combo.addItems(list(DATASET_TYPE.keys())) self.value_type_combo.currentIndexChanged.connect( self.dataset_type_changed) self.value_line_edit = QLineEdit() self.value_line_edit.setPlaceholderText("value") self._set_up_value_validator(False) self.dataset_type_changed(0) self.nx_class_combo = QComboBox() self.edit_button = QPushButton("Edit") edit_button_size = 50 self.edit_button.setMaximumSize(edit_button_size, edit_button_size) self.edit_button.setSizePolicy(fix_horizontal_size) self.edit_button.clicked.connect(self.show_edit_dialog) self.attrs_button = QPushButton("Attrs") self.attrs_button.setMaximumSize(edit_button_size, edit_button_size) self.attrs_button.setSizePolicy(fix_horizontal_size) self.attrs_button.clicked.connect(self.show_attrs_dialog) self.layout = QHBoxLayout() self.layout.addWidget(self.field_name_edit) self.layout.addWidget(self.field_type_combo) self.layout.addWidget(self.value_line_edit) self.layout.addWidget(self.nx_class_combo) self.layout.addWidget(self.edit_button) self.layout.addWidget(self.value_type_combo) self.layout.addWidget(self.units_line_edit) self.layout.addWidget(self.attrs_button) self.layout.setAlignment(Qt.AlignLeft) self.setLayout(self.layout) self.setFrameShadow(QFrame.Raised) self.setFrameShape(QFrame.StyledPanel) # Allow selecting this field widget in a list by clicking on it's contents self.field_name_edit.installEventFilter(self) if parent is not None: self._set_up_name_validator() self.field_name_edit.validator().is_valid.emit(False) self.value_line_edit.installEventFilter(self) self.nx_class_combo.installEventFilter(self) # These cause odd double-clicking behaviour when using an event filter so just connecting to the clicked() signals instead. self.edit_button.clicked.connect(self.something_clicked) self.value_type_combo.highlighted.connect(self.something_clicked) self.field_type_combo.highlighted.connect(self.something_clicked) # Set the layout for the default field type self.field_type_changed()
def __init__( self, node_parent, possible_fields=None, parent: QListWidget = None, parent_dataset: Dataset = None, hide_name_field: bool = False, show_only_f142_stream: bool = False, ): super(FieldWidget, self).__init__(parent) possible_field_names = [] self.default_field_types_dict = {} self.streams_widget: StreamFieldsWidget = None if possible_fields: possible_field_names, default_field_types = zip(*possible_fields) self.default_field_types_dict = dict( zip(possible_field_names, default_field_types)) self._show_only_f142_stream = show_only_f142_stream self._node_parent = node_parent self.edit_dialog = QDialog(parent=self) self.attrs_dialog = FieldAttrsDialog(parent=self) if self.parent() is not None and self.parent().parent() is not None: self.parent().parent().destroyed.connect(self.edit_dialog.close) self.parent().parent().destroyed.connect(self.attrs_dialog.close) self.field_name_edit = FieldNameLineEdit(possible_field_names) if self.default_field_types_dict: self.field_name_edit.textChanged.connect(self.update_default_type) self.hide_name_field = hide_name_field if hide_name_field: self.name = str(uuid.uuid4()) self.units_line_edit = QLineEdit() self.unit_validator = UnitValidator() self.units_line_edit.setValidator(self.unit_validator) self.units_line_edit.setMinimumWidth(20) self.units_line_edit.setMaximumWidth(50) unit_size_policy = QSizePolicy() unit_size_policy.setHorizontalPolicy(QSizePolicy.Preferred) unit_size_policy.setHorizontalStretch(1) self.units_line_edit.setSizePolicy(unit_size_policy) self.unit_validator.is_valid.connect( partial(validate_line_edit, self.units_line_edit)) self.units_line_edit.setPlaceholderText(CommonAttrs.UNITS) self.field_type_combo: QComboBox = QComboBox() self.field_type_combo.addItems([item.value for item in FieldType]) self.field_type_combo.currentIndexChanged.connect( self.field_type_changed) fix_horizontal_size = QSizePolicy() fix_horizontal_size.setHorizontalPolicy(QSizePolicy.Fixed) self.field_type_combo.setSizePolicy(fix_horizontal_size) self.value_type_combo: QComboBox = QComboBox() self.value_type_combo.addItems(list(VALUE_TYPE_TO_NP)) for i, item in enumerate(VALUE_TYPE_TO_NP.keys()): if item == ValueTypes.DOUBLE: self.value_type_combo.setCurrentIndex(i) break self.value_type_combo.currentIndexChanged.connect( self.dataset_type_changed) self.value_line_edit: QLineEdit = QLineEdit() self.value_line_edit.setPlaceholderText("value") value_size_policy = QSizePolicy() value_size_policy.setHorizontalPolicy(QSizePolicy.Preferred) value_size_policy.setHorizontalStretch(2) self.value_line_edit.setSizePolicy(value_size_policy) self._set_up_value_validator(False) self.dataset_type_changed(0) self.nx_class_combo = QComboBox() self.edit_button = QPushButton("Edit") edit_button_size = 50 self.edit_button.setMaximumSize(edit_button_size, edit_button_size) self.edit_button.setSizePolicy(fix_horizontal_size) self.edit_button.clicked.connect(self.show_edit_dialog) self.attrs_button = QPushButton("Attrs") self.attrs_button.setMaximumSize(edit_button_size, edit_button_size) self.attrs_button.setSizePolicy(fix_horizontal_size) self.attrs_button.clicked.connect(self.show_attrs_dialog) self.layout = QHBoxLayout() self.layout.addWidget(self.field_name_edit) self.layout.addWidget(self.field_type_combo) self.layout.addWidget(self.value_line_edit) self.layout.addWidget(self.nx_class_combo) self.layout.addWidget(self.edit_button) self.layout.addWidget(self.value_type_combo) self.layout.addWidget(self.units_line_edit) self.layout.addWidget(self.attrs_button) self.layout.setAlignment(Qt.AlignLeft) self.setLayout(self.layout) self.setFrameShadow(QFrame.Raised) self.setFrameShape(QFrame.StyledPanel) # Allow selecting this field widget in a list by clicking on it's contents self.field_name_edit.installEventFilter(self) existing_objects = [] emit = False if isinstance(parent, QListWidget): for i in range(self.parent().count()): new_field_widget = self.parent().itemWidget( self.parent().item(i)) if new_field_widget is not self and hasattr( new_field_widget, "name"): existing_objects.append(new_field_widget) elif isinstance(self._node_parent, Group): for child in self._node_parent.children: if child is not parent_dataset and hasattr(child, "name"): existing_objects.append(child) emit = True self._set_up_name_validator(existing_objects=existing_objects) self.field_name_edit.validator().is_valid.emit(emit) self.value_line_edit.installEventFilter(self) self.nx_class_combo.installEventFilter(self) # These cause odd double-clicking behaviour when using an event filter so just connecting to the clicked() signals instead. self.edit_button.clicked.connect(self.something_clicked) self.value_type_combo.highlighted.connect(self.something_clicked) self.field_type_combo.highlighted.connect(self.something_clicked) # Set the layout for the default field type self.field_type_changed()
def setupUi(self, pixel_options: PixelOptions = PixelOptions()): """Sets up push buttons and validators for the add component window.""" # Connect the button calls with functions self.ok_button.clicked.connect(self.on_ok) # Disable by default as component name will be missing at the very least. self.ok_button.setEnabled(False) # Set default URL to nexus base classes in web view self.webEngineView.setUrl( QUrl( "http://download.nexusformat.org/doc/html/classes/base_classes/index.html" )) self.placeholder_checkbox.stateChanged.connect( self._disable_fields_and_buttons) self.meshRadioButton.clicked.connect(self.show_mesh_fields) self.boxRadioButton.clicked.connect(self.show_box_fields) self.CylinderRadioButton.clicked.connect(self.show_cylinder_fields) self.noShapeRadioButton.clicked.connect(self.show_no_geometry_fields) self.fileBrowseButton.clicked.connect(self.mesh_file_picker) self.fileLineEdit.setValidator( GeometryFileValidator(GEOMETRY_FILE_TYPES)) self.fileLineEdit.validator().is_valid.connect( partial(validate_line_edit, self.fileLineEdit)) self.fileLineEdit.textChanged.connect( self.populate_pixel_mapping_if_necessary) self.componentTypeComboBox.currentIndexChanged.connect( self.on_nx_class_changed) # Set default geometry type and show the related fields. self.noShapeRadioButton.setChecked(True) self.show_no_geometry_fields() validate_line_edit(self.fileLineEdit, False) self.unitsLineEdit.setValidator( UnitValidator(expected_dimensionality=METRES)) self.unitsLineEdit.validator().is_valid.connect( partial( validate_line_edit, self.unitsLineEdit, tooltip_on_reject="Units not valid", tooltip_on_accept="Units Valid", )) self.componentTypeComboBox.currentIndexChanged.connect( self.change_pixel_options_visibility) # Set whatever the default nx_class is so the fields autocompleter can use the possible fields in the nx_class self.nx_class_changed.connect(self.set_shape_button_visibility) self.on_nx_class_changed() self.fieldsListWidget.itemClicked.connect(self.select_field) self.pixel_options = pixel_options if self.pixel_options: self.pixel_options.setupUi(self.pixelOptionsWidget) self.pixelOptionsWidget.ui = self.pixel_options self.ok_validator = OkValidator(self.noShapeRadioButton, self.meshRadioButton, self.pixel_options.validator) c_group = self._group_container.group if not self.initial_edit: self.setWindowTitle(f"Edit group: {c_group.name}") self.placeholder_checkbox.setChecked(c_group.group_placeholder) self._fill_existing_entries() if (self.get_pixel_visibility_condition() and self.pixel_options and isinstance(c_group, Component)): self.pixel_options.fill_existing_entries(c_group) if c_group.nx_class in NX_CLASSES_WITH_PLACEHOLDERS: self.placeholder_checkbox.setVisible(True) else: self.ok_validator.set_nx_class_valid(False) self.componentTypeComboBox.validator().is_valid.connect( self.ok_validator.set_nx_class_valid) self.componentTypeComboBox.validator().validate( self.componentTypeComboBox.currentText(), 0) self.ok_validator.is_valid.connect(self.ok_button.setEnabled) self.nameLineEdit.validator().is_valid.connect( self.ok_validator.set_name_valid) [ button.clicked.connect(self.ok_validator.validate_ok) for button in [ self.meshRadioButton, self.CylinderRadioButton, self.noShapeRadioButton, self.boxRadioButton, ] ] self.unitsLineEdit.validator().is_valid.connect( self.ok_validator.set_units_valid) self.fileLineEdit.validator().is_valid.connect( self.ok_validator.set_file_valid) self.fileLineEdit.validator().is_valid.connect(self.set_file_valid) # Validate the default values set by the UI self.unitsLineEdit.validator().validate(self.unitsLineEdit.text(), 0) self.nameLineEdit.validator().validate(self.nameLineEdit.text(), 0) if not c_group: self.fileLineEdit.validator().validate(self.fileLineEdit.text(), 0) else: text = (SKIP_VALIDATION if c_group.has_pixel_shape() and not self.fileLineEdit.text() else self.fileLineEdit.text()) self.fileLineEdit.validator().validate(text, 0) self.addFieldPushButton.clicked.connect(self.add_field) self.removeFieldPushButton.clicked.connect(self.remove_field) # Connect the pixel mapping press signal the populate pixel mapping method if self.pixel_options: self.pixel_options.pixel_mapping_button_pressed.connect( self.populate_pixel_mapping_if_necessary) self.cylinderCountSpinBox.valueChanged.connect( self.populate_pixel_mapping_if_necessary) self.meshRadioButton.clicked.connect(self.set_pixel_related_changes) self.CylinderRadioButton.clicked.connect( self.set_pixel_related_changes) self.noShapeRadioButton.clicked.connect(self.set_pixel_related_changes) self.boxRadioButton.clicked.connect(self.set_pixel_related_changes) self.change_pixel_options_visibility() self.setAttribute(Qt.WA_DeleteOnClose)