def save_to_filewriter_json(self): filename = file_dialog(True, "Save Filewriter JSON File", JSON_FILE_TYPES) if filename: dialog = QDialog() dialog.setModal(True) dialog.setLayout(QGridLayout()) command_widget = FilewriterCommandWidget() dialog.layout().addWidget(command_widget) dialog.exec_() ( nexus_file_name, broker, start_time, stop_time, service_id, abort_on_uninitialised_stream, use_swmr, ) = command_widget.get_arguments() with open(filename, "w") as file: filewriter_json_writer.generate_json( self.instrument, file, nexus_file_name=nexus_file_name, broker=broker, start_time=start_time, stop_time=stop_time, service_id=service_id, abort_uninitialised=abort_on_uninitialised_stream, use_swmr=use_swmr, )
def create_new_show(self): w = QDialog() w.setWindowTitle("Create New Show") w.setLayout(QFormLayout()) show_name = QLineEdit("New Show") w.layout().addRow(QLabel("New Show Title:"), show_name) prod_days = QSpinBox() w.layout().addRow(QLabel("Days of production:"), prod_days) calendar_input = QCalendarWidget() w.layout().addRow(QLabel("Start date:")) w.layout().addRow(calendar_input) if self.shows: # If a show has already been created. previous_show = self.shows[-1] prod_days.setValue(previous_show.prod_days) accept = QPushButton("Create") accept.clicked.connect(w.accept) reject = QPushButton("Cancel") reject.clicked.connect(w.reject) w.layout().addRow(accept, reject) if w.exec_() == QDialog.Accepted: print("New show name:", show_name.text(), "Days of pre-production", prod_days.value()) selected_date = calendar_input.selectedDate() start_date = datetime.date(selected_date.year(), selected_date.month(), selected_date.day()) self.shows.append( Show(show_name.text(), prod_days.value(), start_date))
def get_connector(self, importee): """Shows a QDialog to select a connector for the given source file. Mimics similar routine in `spine_io.widgets.import_widget.ImportDialog` Args: importee (str): Label of the file acting as an importee Returns: Asynchronous data reader class for the given importee """ connector_list = [ CSVConnector, ExcelConnector, GdxConnector, JSONConnector ] # add others as needed connector_names = [c.DISPLAY_NAME for c in connector_list] dialog = QDialog(self._toolbox) dialog.setLayout(QVBoxLayout()) connector_list_wg = QListWidget() connector_list_wg.addItems(connector_names) # Set current item in `connector_list_wg` based on file extension _filename, file_extension = os.path.splitext(importee) file_extension = file_extension.lower() if file_extension.startswith(".xls"): row = connector_list.index(ExcelConnector) elif file_extension in (".csv", ".dat", ".txt"): row = connector_list.index(CSVConnector) elif file_extension == ".gdx": row = connector_list.index(GdxConnector) elif file_extension == ".json": row = connector_list.index(JSONConnector) else: row = None if row is not None: connector_list_wg.setCurrentRow(row) button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) button_box.button(QDialogButtonBox.Ok).clicked.connect(dialog.accept) button_box.button(QDialogButtonBox.Cancel).clicked.connect( dialog.reject) connector_list_wg.doubleClicked.connect(dialog.accept) dialog.layout().addWidget(connector_list_wg) dialog.layout().addWidget(button_box) _dirname, filename = os.path.split(importee) dialog.setWindowTitle("Select connector for '{}'".format(filename)) answer = dialog.exec_() if answer: row = connector_list_wg.currentIndex().row() return connector_list[row]
def get_date(self, is_start): w = QDialog() w.setLayout(QFormLayout()) calendar_input = QCalendarWidget() w.layout().addRow(calendar_input) accept_button = QPushButton("Accept") accept_button.clicked.connect(w.accept) cancel_button = QPushButton("Cancel") cancel_button.clicked.connect(w.reject) w.layout().addRow(accept_button, cancel_button) if w.exec() == QDialog.Accepted: selected_date = calendar_input.selectedDate() new_date = datetime.date(selected_date.year(), selected_date.month(), selected_date.day()) print("New date is", new_date) if is_start: self.start_date = new_date self.start_button.setText(str(new_date)) if self.end_date: print("Number of days is", self.end_date - self.start_date) self.calendar_view.setColumnCount( (self.end_date - self.start_date).days) date_labels = [ str(date) for date in date_iterator( self.start_date, self.end_date) ] self.calendar_view.setHorizontalHeaderLabels(date_labels) else: self.end_date = new_date self.end_button.setText(str(new_date)) if self.start_date: print("Number of days is", (self.end_date - self.start_date).days) self.calendar_view.setColumnCount( (self.end_date - self.start_date).days) date_labels = [ str(date) for date in date_iterator( self.start_date, self.end_date) ] self.calendar_view.setHorizontalHeaderLabels(date_labels)
def add_position(self): w = QDialog() w.setWindowTitle("Create New Position") w.setLayout(QFormLayout()) pos_name = QLineEdit("New Position") w.layout().addRow(QLabel("Position Name:"), pos_name) pre_pro_days = QSpinBox() post_pro_days = QSpinBox() w.layout().addRow(QLabel("Days of pre-production:"), pre_pro_days) w.layout().addRow(QLabel("Days of immediate post-production:"), post_pro_days) accept = QPushButton("Create") accept.clicked.connect(w.accept) reject = QPushButton("Cancel") reject.clicked.connect(w.reject) w.layout().addRow(accept, reject) if w.exec_() == QDialog.Accepted: print("Days of pre-production", pre_pro_days.value(), "Days of post-productions", post_pro_days.value()) new_pos_item = QListWidgetItem(pos_name.text()) new_pos_item.setFlags(new_pos_item.flags() | Qt.ItemIsEditable) self.pos_list_widget.addItem(new_pos_item)
def add_crew_member(self): w = QDialog() w.setWindowTitle("Add New Crew Member") w.setLayout(QFormLayout()) crew_name = QLineEdit("New Crew Member") w.layout().addRow(QLabel("Crew Member Name:"), crew_name) specialization = QComboBox() specialization.addItems([ "Directing", "Cinematography", "Producing", "Production Design", "Editing", "Visual Effects" ]) w.layout().addRow(QLabel("Specialization:"), specialization) accept = QPushButton("Create") accept.clicked.connect(w.accept) reject = QPushButton("Cancel") reject.clicked.connect(w.reject) w.layout().addRow(accept, reject) if w.exec_() == QDialog.Accepted: new_crew_item = QListWidgetItem(crew_name.text()) new_crew_item.setFlags(new_crew_item.flags() | Qt.ItemIsEditable) self.crew_list_widget.addItem(new_crew_item)
class FieldWidget(QFrame): # Used for deletion of field something_clicked = Signal() def dataset_type_changed(self, _): self.value_line_edit.validator( ).dataset_type_combo = self.value_type_combo self.value_line_edit.validator( ).field_type_combo = self.field_type_combo self.value_line_edit.validator().validate(self.value_line_edit.text(), 0) 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 _set_up_name_validator(self): field_widgets = [] for i in range(self.parent().count()): field_widgets.append(self.parent().itemWidget( self.parent().item(i))) self.field_name_edit.setValidator( NameValidator(field_widgets, invalid_names=INVALID_FIELD_NAMES)) self.field_name_edit.validator().is_valid.connect( partial( validate_line_edit, self.field_name_edit, tooltip_on_accept="Field name is valid.", tooltip_on_reject=f"Field name is not valid", )) @property def field_type(self) -> FieldType: return FieldType(self.field_type_combo.currentText()) @field_type.setter def field_type(self, field_type: str): self.field_type_combo.setCurrentText(field_type) self.field_type_changed() @property def name(self) -> str: return self.field_name_edit.text() @name.setter def name(self, name: str): self.field_name_edit.setText(name) @property def dtype(self) -> Union[h5py.Datatype, h5py.SoftLink, h5py.Group]: if self.field_type == FieldType.scalar_dataset: return self.value.dtype if self.field_type == FieldType.array_dataset: return self.table_view.model.array.dtype if self.field_type == FieldType.link: return h5py.SoftLink if self.field_type == FieldType.kafka_stream: return h5py.Group @dtype.setter def dtype(self, dtype: h5py.Datatype): type_map = { np.object: "String", np.float64: "Float", np.int64: "Integer" } for item in type_map.keys(): if dtype == item: self.value_type_combo.setCurrentText(type_map[item]) return self.value_type_combo.setCurrentText( next(key for key, value in DATASET_TYPE.items() if value == dtype)) @property def attrs(self) -> h5py.Dataset.attrs: return self.value.attrs @attrs.setter def attrs(self, field: h5py.Dataset): self.attrs_dialog.fill_existing_attrs(field) @property def value(self) -> Union[h5py.Dataset, h5py.Group, h5py.SoftLink]: return_object = None if self.field_type == FieldType.scalar_dataset: dtype = DATASET_TYPE[self.value_type_combo.currentText()] val = self.value_line_edit.text() if dtype == h5py.special_dtype(vlen=str): return_object = create_temporary_in_memory_file( ).create_dataset(name=self.name, dtype=dtype, data=val) else: return_object = create_temporary_in_memory_file( ).create_dataset(name=self.name, dtype=dtype, data=dtype(val)) elif self.field_type == FieldType.array_dataset: # Squeeze the array so 1D arrays can exist. Should not affect dimensional arrays. return_object = create_temporary_in_memory_file().create_dataset( name=self.name, data=np.squeeze(self.table_view.model.array)) elif self.field_type == FieldType.kafka_stream: return_object = self.streams_widget.get_stream_group() elif self.field_type == FieldType.link: return_object = h5py.SoftLink(self.value_line_edit.text()) else: logging.error(f"unknown field type: {self.name}") if self.field_type != FieldType.link: for attr_name, attr_value in self.attrs_dialog.get_attrs().items(): self.instrument.nexus.set_attribute_value( return_object, attr_name, attr_value) if self.units and self.units is not None: self.instrument.nexus.set_attribute_value( return_object, CommonAttrs.UNITS, self.units) return return_object @value.setter def value(self, value): if self.field_type == FieldType.scalar_dataset: self.value_line_edit.setText(to_string(value)) elif self.field_type == FieldType.array_dataset: self.table_view.model.array = value elif self.field_type == FieldType.link: self.value_line_edit.setText(value) @property def units(self): return self.units_line_edit.text() @units.setter def units(self, new_units): self.units_line_edit.setText(new_units) def eventFilter(self, watched: QObject, event: QEvent) -> bool: if event.type() == QEvent.MouseButtonPress: self.something_clicked.emit() return True else: return False def field_type_changed(self): self.edit_dialog = QDialog(parent=self) self._set_up_value_validator(False) if self.field_type == FieldType.scalar_dataset: self.set_visibility(True, False, False, True) elif self.field_type == FieldType.array_dataset: self.set_visibility(False, False, True, True) self.table_view = ArrayDatasetTableWidget() elif self.field_type == FieldType.kafka_stream: self.set_visibility(False, False, True, False, show_name_line_edit=True) self.streams_widget = StreamFieldsWidget(self.edit_dialog) elif self.field_type == FieldType.link: self.set_visibility(True, False, False, False) self._set_up_value_validator(True) elif self.field_type == FieldType.nx_class: self.set_visibility(False, True, False, False) def _set_up_value_validator(self, is_link: bool): self.value_line_edit.setValidator(None) if is_link: self.value_line_edit.setValidator( HDFLocationExistsValidator(self.instrument.nexus.nexus_file, self.field_type_combo)) tooltip_on_accept = "Valid HDF path" tooltip_on_reject = "HDF Path is not valid" else: self.value_line_edit.setValidator( FieldValueValidator( self.field_type_combo, self.value_type_combo, FieldType.scalar_dataset.value, )) tooltip_on_accept = "Value is cast-able to numpy type." tooltip_on_reject = "Value is not cast-able to selected numpy type." self.value_line_edit.validator().is_valid.connect( partial( validate_line_edit, self.value_line_edit, tooltip_on_accept=tooltip_on_accept, tooltip_on_reject=tooltip_on_reject, )) self.value_line_edit.validator().validate(self.value_line_edit.text(), None) def set_visibility( self, show_value_line_edit: bool, show_nx_class_combo: bool, show_edit_button: bool, show_value_type_combo: bool, show_name_line_edit: bool = True, ): self.value_line_edit.setVisible(show_value_line_edit) self.nx_class_combo.setVisible(show_nx_class_combo) self.edit_button.setVisible(show_edit_button) self.value_type_combo.setVisible(show_value_type_combo) self.field_name_edit.setVisible(show_name_line_edit and not self.hide_name_field) def show_edit_dialog(self): if self.field_type == FieldType.array_dataset: self.edit_dialog.setLayout(QGridLayout()) self.table_view.model.update_array_dtype( DATASET_TYPE[self.value_type_combo.currentText()]) self.edit_dialog.layout().addWidget(self.table_view) self.edit_dialog.setWindowTitle( f"Edit {self.value_type_combo.currentText()} Array field") elif self.field_type == FieldType.kafka_stream: self.edit_dialog.setLayout(QFormLayout()) self.edit_dialog.layout().addWidget(self.streams_widget) elif self.field_type.currentText() == FieldType.nx_class: # TODO: show nx class panels pass self.edit_dialog.show() def show_attrs_dialog(self): self.attrs_dialog.show()
class FieldWidget(QFrame): # Used for deletion of field something_clicked = Signal() enable_3d_value_spinbox = Signal(bool) def dataset_type_changed(self, _): self.value_line_edit.validator( ).dataset_type_combo = self.value_type_combo self.value_line_edit.validator( ).field_type_combo = self.field_type_combo self.value_line_edit.validator().validate(self.value_line_edit.text(), 0) 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 _set_up_name_validator( self, existing_objects: List[Union["FieldWidget", FileWriterModule]]): self.field_name_edit.setValidator( NameValidator(existing_objects, invalid_names=INVALID_FIELD_NAMES)) self.field_name_edit.validator().is_valid.connect( partial( validate_line_edit, self.field_name_edit, tooltip_on_accept="Field name is valid.", tooltip_on_reject="Field name is not valid", )) @property def field_type(self) -> FieldType: return FieldType(self.field_type_combo.currentText()) @field_type.setter def field_type(self, field_type: FieldType): self.field_type_combo.setCurrentText(field_type.value) self.field_type_changed() @property def name(self) -> str: return self.field_name_edit.text() @name.setter def name(self, name: str): self.field_name_edit.setText(name) @property def dtype(self) -> str: return self.value_type_combo.currentText() @dtype.setter def dtype(self, dtype: str): self.value_type_combo.setCurrentText(dtype) @property def attrs(self): return self.value.attributes @attrs.setter def attrs(self, field: Dataset): self.attrs_dialog.fill_existing_attrs(field) @property def value(self) -> Union[FileWriterModule, None]: dtype = self.value_type_combo.currentText() return_object: FileWriterModule if self.field_type == FieldType.scalar_dataset: val = self.value_line_edit.text() return_object = Dataset( parent_node=self._node_parent, name=self.name, type=dtype, values=val, ) elif self.field_type == FieldType.array_dataset: # Squeeze the array so 1D arrays can exist. Should not affect dimensional arrays. array = np.squeeze(self.table_view.model.array) return_object = Dataset( parent_node=self._node_parent, name=self.name, type=dtype, values=array, ) elif self.field_type == FieldType.kafka_stream: return_object = self.streams_widget.get_stream_module( self._node_parent) elif self.field_type == FieldType.link: return_object = Link( parent_node=self._node_parent, name=self.name, source=self.value_line_edit.text(), ) else: logging.error(f"unknown field type: {self.name}") return None if self.field_type != FieldType.link: for name, value, dtype in self.attrs_dialog.get_attrs(): return_object.attributes.set_attribute_value( attribute_name=name, attribute_value=value, attribute_type=dtype, ) if self.units and self.units is not None: return_object.attributes.set_attribute_value( CommonAttrs.UNITS, self.units) return return_object @value.setter def value(self, value): if self.field_type == FieldType.scalar_dataset: self.value_line_edit.setText(to_string(value)) elif self.field_type == FieldType.array_dataset: self.table_view.model.array = value elif self.field_type == FieldType.link: self.value_line_edit.setText(value) @property def units(self) -> str: return self.units_line_edit.text() @units.setter def units(self, new_units: str): self.units_line_edit.setText(new_units) def update_default_type(self): self.value_type_combo.setCurrentText( self.default_field_types_dict.get(self.field_name_edit.text(), "double")) def eventFilter(self, watched: QObject, event: QEvent) -> bool: if event.type() == QEvent.MouseButtonPress: self.something_clicked.emit() return True else: return False def field_type_is_scalar(self) -> bool: return self.field_type == FieldType.scalar_dataset def field_type_changed(self): self.edit_dialog = QDialog(parent=self) self.edit_dialog.setModal(True) self._set_up_value_validator(False) self.enable_3d_value_spinbox.emit(not self.field_type_is_scalar()) if self.field_type == FieldType.scalar_dataset: self.set_visibility(True, False, False, True) elif self.field_type == FieldType.array_dataset: self.set_visibility(False, False, True, True) self.table_view = ArrayDatasetTableWidget() elif self.field_type == FieldType.kafka_stream: self.set_visibility(False, False, True, False, show_name_line_edit=True) self.streams_widget = StreamFieldsWidget( self.edit_dialog, show_only_f142_stream=self._show_only_f142_stream) elif self.field_type == FieldType.link: self.set_visibility( True, False, False, False, show_unit_line_edit=False, show_attrs_edit=False, ) self._set_up_value_validator(False) def _set_up_value_validator(self, is_link: bool): self.value_line_edit.setValidator(None) if is_link: return else: self.value_line_edit.setValidator( FieldValueValidator( self.field_type_combo, self.value_type_combo, FieldType.scalar_dataset.value, )) tooltip_on_accept = "Value is cast-able to numpy type." tooltip_on_reject = "Value is not cast-able to selected numpy type." self.value_line_edit.validator().is_valid.connect( partial( validate_line_edit, self.value_line_edit, tooltip_on_accept=tooltip_on_accept, tooltip_on_reject=tooltip_on_reject, )) self.value_line_edit.validator().validate(self.value_line_edit.text(), None) def set_visibility( self, show_value_line_edit: bool, show_nx_class_combo: bool, show_edit_button: bool, show_value_type_combo: bool, show_name_line_edit: bool = True, show_attrs_edit: bool = True, show_unit_line_edit: bool = True, ): self.value_line_edit.setVisible(show_value_line_edit) self.nx_class_combo.setVisible(show_nx_class_combo) self.edit_button.setVisible(show_edit_button) self.value_type_combo.setVisible(show_value_type_combo) self.units_line_edit.setVisible(show_unit_line_edit) self.attrs_button.setVisible(show_attrs_edit) self.field_name_edit.setVisible(show_name_line_edit and not self.hide_name_field) def show_edit_dialog(self): if self.field_type == FieldType.array_dataset: self.edit_dialog.setLayout(QGridLayout()) self.table_view.model.update_array_dtype( VALUE_TYPE_TO_NP[self.value_type_combo.currentText()]) self.edit_dialog.layout().addWidget(self.table_view) self.edit_dialog.setWindowTitle( f"Edit {self.value_type_combo.currentText()} Array field") elif self.field_type == FieldType.kafka_stream: self.edit_dialog.setLayout(QFormLayout()) self.edit_dialog.layout().addWidget(self.streams_widget) if self.edit_dialog.isVisible(): self.edit_dialog.raise_() else: self.edit_dialog.show() def show_attrs_dialog(self): self.attrs_dialog.show()
class DatePicker(QWidget): selectionChanged = Signal() def __init__(self, parent=None): super(DatePicker, self).__init__(parent) self.button = QPushButton(self) icon = QIcon("logo.svg") self.button.setIcon(icon) self.setFixedSize(32, 32) self.button.setFixedSize(32, 32) self.button.setIconSize(QSize(22, 22)) self.__margin__ = 5 self.dialog = QDialog() self.dialog.setWindowFlags(Qt.Window | Qt.FramelessWindowHint | Qt.Popup) self.dialog.setFixedSize(480, 240) self.dialog.setLayout(QHBoxLayout()) self.calender = QCalendarWidget(self) self.dialog.layout().addWidget(self.calender) self.dialog.layout().setContentsMargins(0, 0, 0, 0) self.dialog.layout().setSpacing(0) self.button.clicked.connect(self, SLOT("showCalender()")) self.calender.selectionChanged.connect(self.__emitSelectionChanged__) @Slot() def showCalender(self): print('in show') p = self.mapToGlobal(QPoint(0, self.height() + self.__margin__)) self.dialog.setGeometry(p.x(), p.y(), 0, 0) self.dialog.show() def setIcon(self, icon): if type(icon) is QIcon: self.button.setIcon(icon) elif type(icon) is str: self.button.setIcon(QIcon(icon)) else: raise Exception( 'Wrong argument type, icon should be either PySide2.QtGui.QIcon or str "string"' ) def icon(self): return self.button.icon() def setIconSize(self, iconsize): if type(iconsize) is QSize: self.button.setIconSize(iconsize) elif type(iconsize) is int: self.button.setIcon(QSize(iconsize, iconsize)) elif type(type) is iter: import collections if isinstance(iconsize, collections.Iterable): if len(iconsize) == 1: self.setIconSize(iconsize[0]) elif len(iconsize) == 2: self.setIconSize(QSize(iconsize[0], iconsize[1])) else: raise Exception() else: raise Exception( "Wrong argument type, iconSize should be either PySide2.QtCore.QSize or int value or width and height " "or iterable contains one QSize, one int or two int values for width and height respectively" ) def iconSize(self): return self.button.iconSize() def setFirstDayOfWeek(self, dayOfWeek): if type(dayOfWeek) is Qt.DayOfWeek: self.calender.setFirstDayOfWeek(dayOfWeek) elif type(dayOfWeek) is int: if dayOfWeek < 1 or dayOfWeek > 7: raise Exception( "Wrong argument, dayOfWeek should be from 1 to 7 (Monday --> Sunday)" ) self.calender.setFirstDayOfWeek(Qt.DayOfWeek(dayOfWeek)) else: raise Exception( "Wrong type, dayOfWeek should be either PySide2.QtCore.Qt.DayOf or int (1 --> 7) (Monday --> Sunday)" ) def firstDayOfWeek(self): self.calender.firstDayOfWeek() def selectedDate(self): self.calender.selectedDate() def setSelectedDate(self, args, kwargs): self.calender.setSelectedDate(args, kwargs) def minimumDate(self): self.calender.minimumDate() def setMinimumDate(self): self.calender.setMinimumDate() def selectedDate(self): return self.calender.selectedDate() def __emitSelectionChanged__(self): self.selectionChanged.emit()
def getRundown(self, silent=False): rtext = "" self.rundownCount = 0 for _condi, _pkdf in self.pk_extracted_by_condi.items(): _Np = len(_pkdf.index) _NROI = len(_pkdf.columns) ten_percent = int(_Np / 10) rtext += "{} condition, 10% of peaks count is {} peaks\n".format( _condi, ten_percent) # look at first 5 peaks _firsttenpc = _pkdf.iloc[0:ten_percent].describe().loc["mean"] # look at last 5 peaks _lasttenpc = _pkdf.iloc[-1 - ten_percent:-1].describe().loc["mean"] _tdf = self.tracedata[_condi] _max = _tdf.max() _SD = _tdf.std() _bestSNR = _max / _SD _startSNR = _firsttenpc / _SD _endSNR = _lasttenpc / _SD #print ("ff, lf : {} {}".format(_firstfive, _lastfive)) _rundownRatio = _lasttenpc.div(_firsttenpc).sort_values() self.rundownCount += _rundownRatio[ _rundownRatio < self.rundownThreshold].count() _rd_SNR = pd.concat([_rundownRatio, _bestSNR, _startSNR, _endSNR], axis=1) _rd_SNR.columns = [ 'Rundown', 'Best SNR', 'Initial SNR', 'Final SNR' ] rtext += "Rundown (amplitude ratio: last 10% / first 10%) and signal to noise ratio (start, end)\nfor {} ROIs (ROIs with worst rundown first):\n{}\n\n".format( _NROI, _rd_SNR.round(2).to_string()) rtext += "Total number of traces with rundown worse than threshold ({}): {}\n".format( self.rundownThreshold, self.rundownCount) print(rtext) if not silent: ###Make a pop up window of these results qmb = QDialog() qmb.setWindowTitle('Rundown {}'.format(self.name)) qmb.setGeometry(800, 600, 600, 600) self.rundownText = QtGui.QTextEdit() font = QtGui.QFont() font.setFamily('Courier') font.setFixedPitch(True) font.setPointSize(12) self.rundownText.setCurrentFont(font) self.rundownText.setText(rtext) self.rundownText.setReadOnly(True) #add buttons, make it the right size qmb.layout = QVBoxLayout() qmb.layout.addWidget(self.rundownText) qmb.setLayout(qmb.layout) qmb.exec_()
class MainWindow(Ui_MainWindow, QMainWindow): def __init__(self, instrument: Instrument, nx_classes: Dict): super().__init__() self.instrument = instrument self.nx_classes = nx_classes def setupUi(self, main_window): super().setupUi(main_window) self.export_to_nexus_file_action.triggered.connect( self.save_to_nexus_file) self.open_nexus_file_action.triggered.connect(self.open_nexus_file) self.open_json_file_action.triggered.connect(self.open_json_file) self.open_idf_file_action.triggered.connect(self.open_idf_file) self.export_to_filewriter_JSON_action.triggered.connect( self.save_to_filewriter_json) self.export_to_forwarder_JSON_action.triggered.connect( self.save_to_forwarder_json) # Clear the 3d view when closed QApplication.instance().aboutToQuit.connect(self.sceneWidget.delete) self.widget = silx.gui.hdf5.Hdf5TreeView() self.widget.setAcceptDrops(True) self.widget.setDragEnabled(True) self.treemodel = self.widget.findHdf5TreeModel() self.treemodel.setDatasetDragEnabled(True) self.treemodel.setFileDropEnabled(True) self.treemodel.setFileMoveEnabled(True) self.treemodel.insertH5pyObject(self.instrument.nexus.nexus_file) self.instrument.nexus.file_changed.connect( self.update_nexus_file_structure_view) self.silx_tab_layout.addWidget(self.widget) self.instrument.nexus.show_entries_dialog.connect( self.show_entries_dialog) self.instrument.nexus.component_added.connect( self.sceneWidget.add_component) self.instrument.nexus.component_removed.connect( self.sceneWidget.delete_component) self.component_tree_view_tab.set_up_model(self.instrument) self.instrument.nexus.transformation_changed.connect( self._update_transformations_3d_view) self.widget.setVisible(True) self._set_up_file_writer_control_window(main_window) self.file_writer_control_window = None def _set_up_file_writer_control_window(self, main_window): try: import confluent_kafka # noqa: F401 self.control_file_writer_action = QAction(main_window) self.control_file_writer_action.setText("Control file-writer") self.file_menu.addAction(self.control_file_writer_action) self.control_file_writer_action.triggered.connect( self.show_control_file_writer_window) except ImportError: pass def show_control_file_writer_window(self): if self.file_writer_control_window is None: from nexus_constructor.file_writer_ctrl_window import FileWriterCtrl self.file_writer_ctrl_window = FileWriterCtrl( self.instrument, QSettings("ess", "nexus-constructor")) self.file_writer_ctrl_window.show() def show_edit_component_dialog(self): selected_component = self.component_tree_view_tab.component_tree_view.selectedIndexes( )[0].internalPointer() self.show_add_component_window(selected_component) def show_entries_dialog(self, map_of_entries: dict, nexus_file: h5py.File): """ Shows the entries dialog when loading a nexus file if there are multiple entries. :param map_of_entries: A map of the entry groups, with the key being the name of the group and value being the actual h5py group object. :param nexus_file: A reference to the nexus file. """ self.entries_dialog = QDialog() self.entries_dialog.setMinimumWidth(400) self.entries_dialog.setWindowTitle( "Multiple Entries found. Please choose the entry name from the list." ) combo = QComboBox() # Populate the combo box with the names of the entry groups. [combo.addItem(x) for x in map_of_entries.keys()] ok_button = QPushButton() ok_button.setText("OK") ok_button.clicked.connect(self.entries_dialog.close) def _load_current_entry(): self.instrument.nexus.load_file( map_of_entries[combo.currentText()], nexus_file) self._update_views() # Connect the clicked signal of the ok_button to instrument.load_file and pass the file and entry group object. ok_button.clicked.connect(_load_current_entry) self.entries_dialog.setLayout(QGridLayout()) self.entries_dialog.layout().addWidget(QLabel("Entry:")) self.entries_dialog.layout().addWidget(combo) self.entries_dialog.layout().addWidget(ok_button) self.entries_dialog.show() def update_nexus_file_structure_view(self, nexus_file): self.treemodel.clear() self.treemodel.insertH5pyObject(nexus_file) def save_to_nexus_file(self): filename = file_dialog(True, "Save Nexus File", NEXUS_FILE_TYPES) self.instrument.nexus.save_file(filename) def open_idf_file(self): filename = file_dialog(False, "Open IDF file", {"IDF files": ["xml"]}) self._load_idf(filename) def _load_idf(self, filename): try: builder = NexusBuilder( str(uuid.uuid4()), idf_file=filename, file_in_memory=True, nx_entry_name="entry", ) builder.add_instrument_geometry_from_idf() self.instrument.nexus.load_nexus_file(builder.target_file) self._update_views() QMessageBox.warning( self, "Mantid IDF loaded", "Please manually check the instrument for accuracy.", ) except Exception: QMessageBox.critical(self, "IDF Error", "Error whilst loading IDF file") def save_to_filewriter_json(self): filename = file_dialog(True, "Save Filewriter JSON File", JSON_FILE_TYPES) if filename: with open(filename, "w") as file: filewriter_json_writer.write_nexus_structure_to_json( self.instrument, file) def save_to_forwarder_json(self): filename = file_dialog(True, "Save Forwarder JSON File", JSON_FILE_TYPES) if filename: provider_type, ok_pressed = QInputDialog.getItem( None, "Provider type", "Select provider type for PVs", ["ca", "pva"], 0, False, ) default_broker, ok_pressed = QInputDialog.getText( None, "Default broker", "Default Broker: (This will only be used for streams that do not already have a broker)", text="broker:port", echo=QLineEdit.Normal, ) if ok_pressed: with open(filename, "w") as file: nexus_constructor.json.forwarder_json_writer.generate_forwarder_command( file, self.instrument.nexus.entry, provider_type=provider_type, default_broker=default_broker, ) def open_nexus_file(self): filename = file_dialog(False, "Open Nexus File", NEXUS_FILE_TYPES) existing_file = self.instrument.nexus.nexus_file if self.instrument.nexus.open_file(filename): self._update_views() existing_file.close() def open_json_file(self): filename = file_dialog(False, "Open File Writer JSON File", JSON_FILE_TYPES) if filename: with open(filename, "r") as json_file: json_data = json_file.read() try: nexus_file = json_to_nexus(json_data) except Exception as exception: show_warning_dialog( "Provided file not recognised as valid JSON", "Invalid JSON", f"{exception}", parent=self, ) return existing_file = self.instrument.nexus.nexus_file if self.instrument.nexus.load_nexus_file(nexus_file): self._update_views() existing_file.close() def _update_transformations_3d_view(self): self.sceneWidget.clear_all_transformations() for component in self.instrument.get_component_list(): if component.name != "sample": self.sceneWidget.add_transformation(component.name, component.transform) def _update_views(self): self.sceneWidget.clear_all_transformations() self.sceneWidget.clear_all_components() self.component_tree_view_tab.set_up_model(self.instrument) self._update_3d_view_with_component_shapes() def _update_3d_view_with_component_shapes(self): for component in self.instrument.get_component_list(): shape, positions = component.shape self.sceneWidget.add_component(component.name, shape, positions) self.sceneWidget.add_transformation(component.name, component.transform) def show_add_component_window(self, component: Component = None): self.add_component_window = QDialog() self.add_component_window.ui = AddComponentDialog( self.instrument, self.component_tree_view_tab.component_model, component, nx_classes=self.nx_classes, parent=self, ) self.add_component_window.ui.setupUi(self.add_component_window) self.add_component_window.show()
from hwi_qt.except_hook import except_hook from hwi_qt.logging import log from hwi_qt.selectable_text import SelectableText from hwi_qt.sync_button import SyncButton if __name__ == '__main__': devices = commands.enumerate() print(devices) sys.excepthook = except_hook log.info('Starting hwi-qt') app = QApplication(sys.argv) dialog = QDialog() dialog.layout = QGridLayout() for device in devices: name = device['type'] + '-' + device['fingerprint'] text = SelectableText(name) dialog.layout.addWidget(text, 0, 0) button = SyncButton('Sync', 'Syncing...') dialog.layout.addLayout(button, 0, 1) dialog.setLayout(dialog.layout) dialog.show() sys.exit(app.exec_())