class ObjectExplorer(BaseDialog, SpyderConfigurationAccessor): """Object explorer main widget window.""" CONF_SECTION = 'variable_explorer' def __init__(self, obj, name='', expanded=False, resize_to_contents=True, parent=None, attribute_columns=DEFAULT_ATTR_COLS, attribute_details=DEFAULT_ATTR_DETAILS, readonly=None, reset=False): """ Constructor :param name: name of the object as it will appear in the root node :param expanded: show the first visible root element expanded :param resize_to_contents: resize columns to contents ignoring width of the attributes :param obj: any Python object or variable :param attribute_columns: list of AttributeColumn objects that define which columns are present in the table and their defaults :param attribute_details: list of AttributeDetails objects that define which attributes can be selected in the details pane. :param reset: If true the persistent settings, such as column widths, are reset. """ QDialog.__init__(self, parent=parent) self.setAttribute(Qt.WA_DeleteOnClose) # Options show_callable_attributes = self.get_conf('show_callable_attributes') show_special_attributes = self.get_conf('show_special_attributes') # Model self._attr_cols = attribute_columns self._attr_details = attribute_details self.readonly = readonly self.btn_save_and_close = None self.btn_close = None self._tree_model = TreeModel(obj, obj_name=name, attr_cols=self._attr_cols) self._proxy_tree_model = TreeProxyModel( show_callable_attributes=show_callable_attributes, show_special_attributes=show_special_attributes) self._proxy_tree_model.setSourceModel(self._tree_model) # self._proxy_tree_model.setSortRole(RegistryTableModel.SORT_ROLE) self._proxy_tree_model.setDynamicSortFilter(True) # self._proxy_tree_model.setSortCaseSensitivity(Qt.CaseInsensitive) # Tree widget self.obj_tree = ToggleColumnTreeView() self.obj_tree.setAlternatingRowColors(True) self.obj_tree.setModel(self._proxy_tree_model) self.obj_tree.setSelectionBehavior(QAbstractItemView.SelectRows) self.obj_tree.setUniformRowHeights(True) self.obj_tree.add_header_context_menu() # Views self._setup_actions() self._setup_menu(show_callable_attributes=show_callable_attributes, show_special_attributes=show_special_attributes) self._setup_views() if name: name = "{} -".format(name) self.setWindowTitle("{} {}".format(name, EDITOR_NAME)) self.setWindowFlags(Qt.Window) self._resize_to_contents = resize_to_contents self._readViewSettings(reset=reset) # Update views with model self.toggle_show_special_attribute_action.setChecked( show_special_attributes) self.toggle_show_callable_action.setChecked(show_callable_attributes) # Select first row so that a hidden root node will not be selected. first_row_index = self._proxy_tree_model.firstItemIndex() self.obj_tree.setCurrentIndex(first_row_index) if self._tree_model.inspectedNodeIsVisible or expanded: self.obj_tree.expand(first_row_index) def get_value(self): """Get editor current object state.""" return self._tree_model.inspectedItem.obj def _make_show_column_function(self, column_idx): """Creates a function that shows or hides a column.""" show_column = lambda checked: self.obj_tree.setColumnHidden( column_idx, not checked) return show_column def _setup_actions(self): """Creates the main window actions.""" # Show/hide callable objects self.toggle_show_callable_action = QAction( _("Show callable attributes"), self, checkable=True, shortcut=QKeySequence("Alt+C"), statusTip=_("Shows/hides attributes that are callable " "(functions, methods, etc)")) self.toggle_show_callable_action.toggled.connect( self._proxy_tree_model.setShowCallables) self.toggle_show_callable_action.toggled.connect( self.obj_tree.resize_columns_to_contents) # Show/hide special attributes self.toggle_show_special_attribute_action = QAction( _("Show __special__ attributes"), self, checkable=True, shortcut=QKeySequence("Alt+S"), statusTip=_("Shows or hides __special__ attributes")) self.toggle_show_special_attribute_action.toggled.connect( self._proxy_tree_model.setShowSpecialAttributes) self.toggle_show_special_attribute_action.toggled.connect( self.obj_tree.resize_columns_to_contents) def _setup_menu(self, show_callable_attributes=False, show_special_attributes=False): """Sets up the main menu.""" self.tools_layout = QHBoxLayout() callable_attributes = create_toolbutton( self, text=_("Show callable attributes"), icon=ima.icon("class"), toggled=self._toggle_show_callable_attributes_action) callable_attributes.setCheckable(True) callable_attributes.setChecked(show_callable_attributes) self.tools_layout.addWidget(callable_attributes) special_attributes = create_toolbutton( self, text=_("Show __special__ attributes"), icon=ima.icon("private2"), toggled=self._toggle_show_special_attributes_action) special_attributes.setCheckable(True) special_attributes.setChecked(show_special_attributes) self.tools_layout.addWidget(special_attributes) self.tools_layout.addStretch() self.options_button = create_toolbutton(self, text=_('Options'), icon=ima.icon('tooloptions')) self.options_button.setPopupMode(QToolButton.InstantPopup) self.show_cols_submenu = QMenu(self) self.options_button.setMenu(self.show_cols_submenu) # Don't show menu arrow and remove padding if is_dark_interface(): self.options_button.setStyleSheet( ("QToolButton::menu-indicator{image: none;}\n" "QToolButton{padding: 3px;}")) else: self.options_button.setStyleSheet( "QToolButton::menu-indicator{image: none;}") self.tools_layout.addWidget(self.options_button) @Slot() def _toggle_show_callable_attributes_action(self): """Toggle show callable atributes action.""" action_checked = not self.toggle_show_callable_action.isChecked() self.toggle_show_callable_action.setChecked(action_checked) self.set_conf('show_callable_attributes', action_checked) @Slot() def _toggle_show_special_attributes_action(self): """Toggle show special attributes action.""" action_checked = ( not self.toggle_show_special_attribute_action.isChecked()) self.toggle_show_special_attribute_action.setChecked(action_checked) self.set_conf('show_special_attributes', action_checked) def _setup_views(self): """Creates the UI widgets.""" self.central_splitter = QSplitter(self, orientation=Qt.Vertical) layout = create_plugin_layout(self.tools_layout, self.central_splitter) self.setLayout(layout) # Stretch last column? # It doesn't play nice when columns are hidden and then shown again. obj_tree_header = self.obj_tree.header() obj_tree_header.setSectionsMovable(True) obj_tree_header.setStretchLastSection(False) add_actions(self.show_cols_submenu, self.obj_tree.toggle_column_actions_group.actions()) self.central_splitter.addWidget(self.obj_tree) # Bottom pane bottom_pane_widget = QWidget() bottom_layout = QHBoxLayout() bottom_layout.setSpacing(0) bottom_layout.setContentsMargins(5, 5, 5, 5) # left top right bottom bottom_pane_widget.setLayout(bottom_layout) self.central_splitter.addWidget(bottom_pane_widget) group_box = QGroupBox(_("Details")) bottom_layout.addWidget(group_box) v_group_layout = QVBoxLayout() h_group_layout = QHBoxLayout() h_group_layout.setContentsMargins(2, 2, 2, 2) # left top right bottom group_box.setLayout(v_group_layout) v_group_layout.addLayout(h_group_layout) # Radio buttons radio_widget = QWidget() radio_layout = QVBoxLayout() radio_layout.setContentsMargins(0, 0, 0, 0) # left top right bottom radio_widget.setLayout(radio_layout) self.button_group = QButtonGroup(self) for button_id, attr_detail in enumerate(self._attr_details): radio_button = QRadioButton(attr_detail.name) radio_layout.addWidget(radio_button) self.button_group.addButton(radio_button, button_id) self.button_group.buttonClicked[int].connect( self._change_details_field) self.button_group.button(0).setChecked(True) radio_layout.addStretch(1) h_group_layout.addWidget(radio_widget) # Editor widget self.editor = SimpleCodeEditor(self) self.editor.setReadOnly(True) h_group_layout.addWidget(self.editor) # Save and close buttons btn_layout = QHBoxLayout() btn_layout.addStretch() if not self.readonly: self.btn_save_and_close = QPushButton(_('Save and Close')) self.btn_save_and_close.setDisabled(True) self.btn_save_and_close.clicked.connect(self.accept) btn_layout.addWidget(self.btn_save_and_close) self.btn_close = QPushButton(_('Close')) self.btn_close.setAutoDefault(True) self.btn_close.setDefault(True) self.btn_close.clicked.connect(self.reject) btn_layout.addWidget(self.btn_close) v_group_layout.addLayout(btn_layout) # Splitter parameters self.central_splitter.setCollapsible(0, False) self.central_splitter.setCollapsible(1, True) self.central_splitter.setSizes([500, 320]) # Connect signals # Keep a temporary reference of the selection_model to prevent # segfault in PySide. # See http://permalink.gmane.org/gmane.comp.lib.qt.pyside.devel/222 selection_model = self.obj_tree.selectionModel() selection_model.currentChanged.connect(self._update_details) # Check if the values of the model have been changed self._proxy_tree_model.sig_setting_data.connect( self.save_and_close_enable) self._proxy_tree_model.sig_update_details.connect( self._update_details_for_item) # End of setup_methods def _readViewSettings(self, reset=False): """ Reads the persistent program settings. :param reset: If True, the program resets to its default settings. """ pos = QPoint(20, 20) window_size = QSize(825, 650) details_button_idx = 0 header = self.obj_tree.header() header_restored = False if reset: logger.debug("Resetting persistent view settings") else: pos = pos window_size = window_size details_button_idx = details_button_idx # splitter_state = settings.value("central_splitter/state") splitter_state = None if splitter_state: self.central_splitter.restoreState(splitter_state) # header_restored = self.obj_tree.read_view_settings( # 'table/header_state', # settings, reset) header_restored = False if not header_restored: column_sizes = [col.width for col in self._attr_cols] column_visible = [col.col_visible for col in self._attr_cols] for idx, size in enumerate(column_sizes): if not self._resize_to_contents and size > 0: # Just in case header.resizeSection(idx, size) else: header.resizeSections(QHeaderView.ResizeToContents) break for idx, visible in enumerate(column_visible): elem = self.obj_tree.toggle_column_actions_group.actions()[idx] elem.setChecked(visible) self.resize(window_size) button = self.button_group.button(details_button_idx) if button is not None: button.setChecked(True) @Slot() def save_and_close_enable(self): """Handle the data change event to enable the save and close button.""" if self.btn_save_and_close: self.btn_save_and_close.setEnabled(True) self.btn_save_and_close.setAutoDefault(True) self.btn_save_and_close.setDefault(True) @Slot(QModelIndex, QModelIndex) def _update_details(self, current_index, _previous_index): """Shows the object details in the editor given an index.""" tree_item = self._proxy_tree_model.treeItem(current_index) self._update_details_for_item(tree_item) def _change_details_field(self, _button_id=None): """Changes the field that is displayed in the details pane.""" # logger.debug("_change_details_field: {}".format(_button_id)) current_index = self.obj_tree.selectionModel().currentIndex() tree_item = self._proxy_tree_model.treeItem(current_index) self._update_details_for_item(tree_item) @Slot(TreeItem) def _update_details_for_item(self, tree_item): """Shows the object details in the editor given an tree_item.""" try: # obj = tree_item.obj button_id = self.button_group.checkedId() assert button_id >= 0, ("No radio button selected. " "Please report this bug.") attr_details = self._attr_details[button_id] data = attr_details.data_fn(tree_item) self.editor.setPlainText(data) self.editor.setWordWrapMode(attr_details.line_wrap) self.editor.setup_editor( font=get_font(font_size_delta=DEFAULT_SMALL_DELTA), show_blanks=False, color_scheme=CONF.get('appearance', 'selected'), scroll_past_end=False, ) self.editor.set_text(data) if attr_details.name == 'Source code': self.editor.set_language('Python') else: self.editor.set_language('Rst') except Exception as ex: self.editor.setStyleSheet("color: red;") stack_trace = traceback.format_exc() self.editor.setPlainText("{}\n\n{}".format(ex, stack_trace)) self.editor.setWordWrapMode( QTextOption.WrapAtWordBoundaryOrAnywhere) @classmethod def create_explorer(cls, *args, **kwargs): """ Creates and shows and ObjectExplorer window. The *args and **kwargs will be passed to the ObjectExplorer constructor A (class attribute) reference to the browser window is kept to prevent it from being garbage-collected. """ object_explorer = cls(*args, **kwargs) object_explorer.exec_() return object_explorer
class PlotSettingsWidget(QWidget): def __init__(self, settings, plotWidget, parent=None): super().__init__(parent) self.mainwindow = parent self.plotWidget = plotWidget # xmin self.xminLabel = QLabel(self.tr('xmin:')) self.xminSpinBox = CoordSpinBox() self.xminLabel.setBuddy(self.xminSpinBox) self.xminSpinBox.editingFinished.connect(self.change_limits) # xmax self.xmaxLabel = QLabel(self.tr('xmax:')) self.xmaxSpinBox = CoordSpinBox() self.xmaxLabel.setBuddy(self.xmaxSpinBox) self.xmaxSpinBox.editingFinished.connect(self.change_limits) # ymin self.yminLabel = QLabel(self.tr('ymin:')) self.yminSpinBox = CoordSpinBox() self.yminLabel.setBuddy(self.yminSpinBox) self.yminSpinBox.editingFinished.connect(self.change_limits) # ymax self.ymaxLabel = QLabel(self.tr('ymax:')) self.ymaxSpinBox = CoordSpinBox() self.ymaxLabel.setBuddy(self.ymaxSpinBox) self.ymaxSpinBox.editingFinished.connect(self.change_limits) # Autoscale Radio Group self.autoscaleButtonGroup = QButtonGroup() # Autoscale Group Box self.autoscaleGroupBox = QGroupBox() # autoscale self.autoscaleRadioButton = QRadioButton(self.tr("autoscale")) self.autoscaleButtonGroup.addButton(self.autoscaleRadioButton) # autotrack self.autoscrollRadioButton = QRadioButton(self.tr("autoscroll")) self.autoscaleButtonGroup.addButton(self.autoscrollRadioButton) # no autoscale self.manualscaleRadioButton = QRadioButton(self.tr("manual")) self.autoscaleButtonGroup.addButton(self.manualscaleRadioButton) layout = QVBoxLayout() layout.addWidget(self.autoscaleRadioButton) layout.addWidget(self.autoscrollRadioButton) layout.addWidget(self.manualscaleRadioButton) self.autoscaleGroupBox.setLayout(layout) # Layout layout = QGridLayout() layout.addWidget(self.xminLabel, 1, 0) layout.addWidget(self.xminSpinBox, 1, 1) layout.addWidget(self.xmaxLabel, 2, 0) layout.addWidget(self.xmaxSpinBox, 2, 1) layout.addWidget(self.yminLabel, 3, 0) layout.addWidget(self.yminSpinBox, 3, 1) layout.addWidget(self.ymaxLabel, 4, 0) layout.addWidget(self.ymaxSpinBox, 4, 1) layout.addWidget(self.autoscaleGroupBox, 5, 0, 1, 2) layout.setRowStretch(6, 1) self.setLayout(layout) # settings self.settings = settings self.settings.add_handler(S_XMIN, self.xminSpinBox) self.settings.add_handler(S_XMAX, self.xmaxSpinBox) self.settings.add_handler(S_YMIN, self.yminSpinBox) self.settings.add_handler(S_YMAX, self.ymaxSpinBox) self.settings.add_handler(S_AUTOSCALE, self.autoscaleButtonGroup) def refresh(self, state): pass def change_limits(self): if self.autoscale != AUTOSCALE_COMPLETE: self.plotWidget.xmin = self.xmin self.plotWidget.xmax = self.xmax self.plotWidget.ymin = self.ymin self.plotWidget.ymax = self.ymax self.plotWidget.draw() @property def xmin(self): return self.xminSpinBox.value() @property def xmax(self): return self.xmaxSpinBox.value() @property def ymin(self): return self.yminSpinBox.value() @property def ymax(self): return self.ymaxSpinBox.value() @property def autoscale(self): return self.autoscaleButtonGroup.checkedId()
class DataCorrectionsWidget(BaseWidget): """ Widget that presents data correction options to the user. """ ## Widget name name = "Data Corrections" _old_backgnd_sub = None _old_norm_button = None incident_beam_norm_grp = None def __init__(self, parent=None, state=None, settings=None, data_type=None): super(DataCorrectionsWidget, self).__init__(parent, state, settings, data_type=data_type) class DataCorrsFrame(QFrame): def __init__(self, parent=None): QFrame.__init__(self, parent) self.ui = load_ui(__file__, '../../../ui/inelastic/dgs_data_corrections.ui', baseinstance=self) self._content = DataCorrsFrame(self) self._layout.addWidget(self._content) self.initialize_content() self._instrument_name = settings.instrument_name if state is not None: self.set_state(state) else: self.set_state(DataCorrectionsScript(self._instrument_name)) def initialize_content(self): # Set some validators self._content.monint_low_edit.setValidator(QIntValidator(self._content.monint_low_edit)) self._content.monint_high_edit.setValidator(QIntValidator(self._content.monint_high_edit)) self._content.tof_start_edit.setValidator(QIntValidator(self._content.tof_start_edit)) self._content.tof_end_edit.setValidator(QIntValidator(self._content.tof_end_edit)) # Make group for incident beam normalisation radio buttons self.incident_beam_norm_grp = QButtonGroup() self.incident_beam_norm_grp.addButton(self._content.none_rb, 0) self.incident_beam_norm_grp.addButton(self._content.current_rb, 1) self.incident_beam_norm_grp.addButton(self._content.monitor1_rb, 2) self._monitor_intrange_widgets_state(self._content.monitor1_rb.isChecked()) self._content.monitor1_rb.toggled.connect(self._monitor_intrange_widgets_state) self._detvan_intrange_widgets_state(self._content.van_int_cb.isChecked()) self._content.van_int_cb.toggled.connect(self._detvan_intrange_widgets_state) self._content.use_procdetvan_cb.toggled.connect(self._detvan_widgets_opp_state) self._save_detvan_widgets_state(self._content.save_procdetvan_cb.isChecked()) self._content.save_procdetvan_cb.toggled.connect(self._save_detvan_widgets_state) # Connections self._content.van_input_browse.clicked.connect(self._detvan_browse) self._content.save_procdetvan_save.clicked.connect(self._save_procdetvan_save) def _monitor_intrange_widgets_state(self, state=False): self._content.monint_label.setEnabled(state) self._content.monint_low_edit.setEnabled(state) self._content.monint_high_edit.setEnabled(state) def _detvan_intrange_widgets_state(self, state=False): self._content.van_int_range_label.setEnabled(state) self._content.van_int_range_low_edit.setEnabled(state) self._content.van_int_range_high_edit.setEnabled(state) self._content.van_int_range_units_cb.setEnabled(state) def _detvan_widgets_opp_state(self, state=False): self._content.van_int_cb.setEnabled(not state) if self._content.van_int_cb.isChecked(): self._detvan_intrange_widgets_state(not state) self._content.van_int_cb.setChecked(False) self._content.save_procdetvan_cb.setEnabled(not state) if self._content.save_procdetvan_cb.isChecked(): self._content.save_procdetvan_cb.setChecked(False) def _save_detvan_widgets_state(self, state=False): self._content.save_procdetvan_label.setEnabled(state) self._content.save_procdetvan_edit.setEnabled(state) self._content.save_procdetvan_save.setEnabled(state) def _detvan_browse(self): fname = self.data_browse_dialog() if fname: self._content.van_input_edit.setText(fname) def _save_procdetvan_save(self): fname = self.data_save_dialog("*.nxs") if fname: self._content.save_procdetvan_edit.setText(fname) def set_state(self, state): """ Populate the UI elements with the data from the given state. @param state: DataCorrectionsScript object """ self._content.filter_bad_pulses_chkbox.setChecked(state.filter_bad_pulses) button_index = DataCorrectionsScript.INCIDENT_BEAM_NORM_TYPES.index(state.incident_beam_norm) cbutton = self.incident_beam_norm_grp.button(button_index) cbutton.setChecked(True) self._content.monint_low_edit.setText(str(state.monitor_int_low)) self._content.monint_high_edit.setText(str(state.monitor_int_high)) self._content.background_sub_gb.setChecked(state.tib_subtraction) self._content.tof_start_edit.setText(str(state.tib_tof_start)) self._content.tof_end_edit.setText(str(state.tib_tof_end)) self._content.correct_kikf_cb.setChecked(state.correct_kikf) self._content.van_input_edit.setText(state.detector_vanadium) self._content.van_int_cb.setChecked(state.detvan_integration) self._content.van_int_range_low_edit.setText(str(state.detvan_int_range_low)) self._content.van_int_range_high_edit.setText(str(state.detvan_int_range_high)) entry_index = self._content.van_int_range_units_cb.findText(state.detvan_int_range_units) self._content.van_int_range_units_cb.setCurrentIndex(entry_index) self._content.save_procdetvan_cb.setChecked(state.save_proc_detvan) self._content.save_procdetvan_edit.setText(str(state.save_proc_detvan_file)) self._content.use_procdetvan_cb.setChecked(state.use_proc_detvan) def get_state(self): """ Returns an object with the state of the interface """ d = DataCorrectionsScript(self._instrument_name) d.filter_bad_pulses = self._content.filter_bad_pulses_chkbox.isChecked() d.incident_beam_norm = DataCorrectionsScript.INCIDENT_BEAM_NORM_TYPES[self.incident_beam_norm_grp.checkedId()] d.monitor_int_low = util._check_and_get_float_line_edit(self._content.monint_low_edit) d.monitor_int_high = util._check_and_get_float_line_edit(self._content.monint_high_edit) d.tib_subtraction = self._content.background_sub_gb.isChecked() d.tib_tof_start = util._check_and_get_float_line_edit(self._content.tof_start_edit) d.tib_tof_end = util._check_and_get_float_line_edit(self._content.tof_end_edit) d.correct_kikf = self._content.correct_kikf_cb.isChecked() d.detector_vanadium = self._content.van_input_edit.text() d.detvan_integration = self._content.van_int_cb.isChecked() d.detvan_int_range_low = util._check_and_get_float_line_edit(self._content.van_int_range_low_edit) d.detvan_int_range_high = util._check_and_get_float_line_edit(self._content.van_int_range_high_edit) d.detvan_int_range_units = self._content.van_int_range_units_cb.currentText() d.save_proc_detvan = self._content.save_procdetvan_cb.isChecked() d.save_proc_detvan_file = self._content.save_procdetvan_edit.text() d.use_proc_detvan = self._content.use_procdetvan_cb.isChecked() return d def live_button_toggled_actions(self,checked): if checked: self._old_norm_button = self.incident_beam_norm_grp.checkedId() self._old_backgnd_sub = self._content.background_sub_gb.isChecked() self._content.none_rb.setChecked(True) self._content.background_sub_gb.setChecked(False) else: try: self.incident_beam_norm_grp.button(self._old_norm_button).setChecked(True) self._content.background_sub_gb.setChecked(self._old_backgnd_sub) except: # This is for if the live button started out checked pass self._content.incident_beam_norm_gb.setEnabled(not checked) self._content.background_sub_gb.setEnabled(not checked)
class DataCorrectionsWidget(BaseWidget): """ Widget that presents data correction options to the user. """ ## Widget name name = "Data Corrections" _old_backgnd_sub = None _old_norm_button = None incident_beam_norm_grp = None def __init__(self, parent=None, state=None, settings=None, data_type=None): super(DataCorrectionsWidget, self).__init__(parent, state, settings, data_type=data_type) class DataCorrsFrame(QFrame): def __init__(self, parent=None): QFrame.__init__(self, parent) self.ui = load_ui( __file__, '../../../ui/inelastic/dgs_data_corrections.ui', baseinstance=self) self._content = DataCorrsFrame(self) self._layout.addWidget(self._content) self.initialize_content() self._instrument_name = settings.instrument_name if state is not None: self.set_state(state) else: self.set_state(DataCorrectionsScript(self._instrument_name)) def initialize_content(self): # Set some validators self._content.monint_low_edit.setValidator( QIntValidator(self._content.monint_low_edit)) self._content.monint_high_edit.setValidator( QIntValidator(self._content.monint_high_edit)) self._content.tof_start_edit.setValidator( QIntValidator(self._content.tof_start_edit)) self._content.tof_end_edit.setValidator( QIntValidator(self._content.tof_end_edit)) # Make group for incident beam normalisation radio buttons self.incident_beam_norm_grp = QButtonGroup() self.incident_beam_norm_grp.addButton(self._content.none_rb, 0) self.incident_beam_norm_grp.addButton(self._content.current_rb, 1) self.incident_beam_norm_grp.addButton(self._content.monitor1_rb, 2) self._monitor_intrange_widgets_state( self._content.monitor1_rb.isChecked()) self._content.monitor1_rb.toggled.connect( self._monitor_intrange_widgets_state) self._detvan_intrange_widgets_state( self._content.van_int_cb.isChecked()) self._content.van_int_cb.toggled.connect( self._detvan_intrange_widgets_state) self._content.use_procdetvan_cb.toggled.connect( self._detvan_widgets_opp_state) self._save_detvan_widgets_state( self._content.save_procdetvan_cb.isChecked()) self._content.save_procdetvan_cb.toggled.connect( self._save_detvan_widgets_state) # Connections self._content.van_input_browse.clicked.connect(self._detvan_browse) self._content.save_procdetvan_save.clicked.connect( self._save_procdetvan_save) def _monitor_intrange_widgets_state(self, state=False): self._content.monint_label.setEnabled(state) self._content.monint_low_edit.setEnabled(state) self._content.monint_high_edit.setEnabled(state) def _detvan_intrange_widgets_state(self, state=False): self._content.van_int_range_label.setEnabled(state) self._content.van_int_range_low_edit.setEnabled(state) self._content.van_int_range_high_edit.setEnabled(state) self._content.van_int_range_units_cb.setEnabled(state) def _detvan_widgets_opp_state(self, state=False): self._content.van_int_cb.setEnabled(not state) if self._content.van_int_cb.isChecked(): self._detvan_intrange_widgets_state(not state) self._content.van_int_cb.setChecked(False) self._content.save_procdetvan_cb.setEnabled(not state) if self._content.save_procdetvan_cb.isChecked(): self._content.save_procdetvan_cb.setChecked(False) def _save_detvan_widgets_state(self, state=False): self._content.save_procdetvan_label.setEnabled(state) self._content.save_procdetvan_edit.setEnabled(state) self._content.save_procdetvan_save.setEnabled(state) def _detvan_browse(self): fname = self.data_browse_dialog() if fname: self._content.van_input_edit.setText(fname) def _save_procdetvan_save(self): fname = self.data_save_dialog("*.nxs") if fname: self._content.save_procdetvan_edit.setText(fname) def set_state(self, state): """ Populate the UI elements with the data from the given state. @param state: DataCorrectionsScript object """ self._content.filter_bad_pulses_chkbox.setChecked( state.filter_bad_pulses) button_index = DataCorrectionsScript.INCIDENT_BEAM_NORM_TYPES.index( state.incident_beam_norm) cbutton = self.incident_beam_norm_grp.button(button_index) cbutton.setChecked(True) self._content.monint_low_edit.setText(str(state.monitor_int_low)) self._content.monint_high_edit.setText(str(state.monitor_int_high)) self._content.background_sub_gb.setChecked(state.tib_subtraction) self._content.tof_start_edit.setText(str(state.tib_tof_start)) self._content.tof_end_edit.setText(str(state.tib_tof_end)) self._content.correct_kikf_cb.setChecked(state.correct_kikf) self._content.van_input_edit.setText(state.detector_vanadium) self._content.van_int_cb.setChecked(state.detvan_integration) self._content.van_int_range_low_edit.setText( str(state.detvan_int_range_low)) self._content.van_int_range_high_edit.setText( str(state.detvan_int_range_high)) entry_index = self._content.van_int_range_units_cb.findText( state.detvan_int_range_units) self._content.van_int_range_units_cb.setCurrentIndex(entry_index) self._content.save_procdetvan_cb.setChecked(state.save_proc_detvan) self._content.save_procdetvan_edit.setText( str(state.save_proc_detvan_file)) self._content.use_procdetvan_cb.setChecked(state.use_proc_detvan) def get_state(self): """ Returns an object with the state of the interface """ d = DataCorrectionsScript(self._instrument_name) d.filter_bad_pulses = self._content.filter_bad_pulses_chkbox.isChecked( ) d.incident_beam_norm = DataCorrectionsScript.INCIDENT_BEAM_NORM_TYPES[ self.incident_beam_norm_grp.checkedId()] d.monitor_int_low = util._check_and_get_float_line_edit( self._content.monint_low_edit) d.monitor_int_high = util._check_and_get_float_line_edit( self._content.monint_high_edit) d.tib_subtraction = self._content.background_sub_gb.isChecked() d.tib_tof_start = util._check_and_get_float_line_edit( self._content.tof_start_edit) d.tib_tof_end = util._check_and_get_float_line_edit( self._content.tof_end_edit) d.correct_kikf = self._content.correct_kikf_cb.isChecked() d.detector_vanadium = self._content.van_input_edit.text() d.detvan_integration = self._content.van_int_cb.isChecked() d.detvan_int_range_low = util._check_and_get_float_line_edit( self._content.van_int_range_low_edit) d.detvan_int_range_high = util._check_and_get_float_line_edit( self._content.van_int_range_high_edit) d.detvan_int_range_units = self._content.van_int_range_units_cb.currentText( ) d.save_proc_detvan = self._content.save_procdetvan_cb.isChecked() d.save_proc_detvan_file = self._content.save_procdetvan_edit.text() d.use_proc_detvan = self._content.use_procdetvan_cb.isChecked() return d def live_button_toggled_actions(self, checked): if checked: self._old_norm_button = self.incident_beam_norm_grp.checkedId() self._old_backgnd_sub = self._content.background_sub_gb.isChecked() self._content.none_rb.setChecked(True) self._content.background_sub_gb.setChecked(False) else: try: self.incident_beam_norm_grp.button( self._old_norm_button).setChecked(True) self._content.background_sub_gb.setChecked( self._old_backgnd_sub) except: # This is for if the live button started out checked pass self._content.incident_beam_norm_gb.setEnabled(not checked) self._content.background_sub_gb.setEnabled(not checked)
class NappingDialog(QDialog): class SelectionMode(IntEnum): FILE = 0 DIR = 1 class MatchingStrategy(Enum): ALPHABETICAL = 'Alphabetical order' FILENAME = 'Filename (without extension)' REGEX = 'Python regular expression (RegEx)' class TransformType(Enum): EUCLIDEAN = 'Euclidean (rotation, translation)' SIMILARITY = 'Similarity (Euclidean transform + uniform scaling)' AFFINE = 'Affine (Similarity transform + non-uniform scaling + shear)' SELECTION_MODE_SETTING = 'registrationDialog/selectionMode' MATCHING_STRATEGY_SETTING = 'registrationDialog/matchingStrategy' SOURCE_IMAGES_SETTING = 'registrationDialog/sourceImages' SOURCE_REGEX_SETTING = 'registrationDialog/sourceRegex' TARGET_IMAGES_SETTING = 'registrationDialog/targetImages' TARGET_REGEX_SETTING = 'registrationDialog/targetRegex' CONTROL_POINTS_DEST_SETTING = 'registrationDialog/controlPointsDest' JOINT_TRANSFORM_DEST_SETTING = 'registrationDialog/jointTransformDest' TRANSFORM_TYPE_SETTING = 'registrationDialog/transformType' SOURCE_COORDS_SETTING = 'registrationDialog/sourceCoords' SOURCE_COORDS_REGEX_SETTING = 'registrationDialog/sourceCoordsRegex' TRANSFORMED_COORDS_DEST_SETTING = 'registrationDialog/transformedCoordsDest' PRE_TRANSFORM_SETTING = 'registrationDialog/preTransformFile' POST_TRANSFORM_SETTING = 'registrationDialog/postTransformFile' DEFAULT_SELECTION_MODE = SelectionMode.FILE DEFAULT_MATCHING_STRATEGY = MatchingStrategy.FILENAME DEFAULT_SOURCE_IMAGES = '' DEFAULT_SOURCE_REGEX = '' DEFAULT_TARGET_IMAGES = '' DEFAULT_TARGET_REGEX = '' DEFAULT_CONTROL_POINTS_DEST = '' DEFAULT_JOINT_TRANSFORM_DEST = '' DEFAULT_TRANSFORM_TYPE = TransformType.SIMILARITY DEFAULT_SOURCE_COORDS = '' DEFAULT_SOURCE_COORDS_REGEX = '' DEFAULT_TRANSFORMED_COORDS_DEST = '' DEFAULT_PRE_TRANSFORM = '' DEFAULT_POST_TRANSFORM = '' def __init__(self, settings: QSettings, parent: Optional[QObject] = None): # noinspection PyArgumentList super(NappingDialog, self).__init__(parent) checked_selection_mode = NappingDialog.SelectionMode( int( settings.value( self.SELECTION_MODE_SETTING, defaultValue=self.DEFAULT_SELECTION_MODE.value))) self._file_selection_mode_button = QRadioButton( 'Single file pair', self) self._file_selection_mode_button.setChecked( checked_selection_mode == NappingDialog.SelectionMode.FILE) self._dir_selection_mode_button = QRadioButton( 'Directories (multiple file pairs)', self) self._dir_selection_mode_button.setChecked( checked_selection_mode == NappingDialog.SelectionMode.DIR) self._selection_mode_buttons_group = QButtonGroup(self) self._selection_mode_buttons_group.addButton( self._file_selection_mode_button, NappingDialog.SelectionMode.FILE) self._selection_mode_buttons_group.addButton( self._dir_selection_mode_button, NappingDialog.SelectionMode.DIR) # noinspection PyUnresolvedReferences self._selection_mode_buttons_group.buttonClicked.connect( lambda _: self.refresh()) matching_strategy_combo_box_current_text = str( settings.value(self.MATCHING_STRATEGY_SETTING, defaultValue=self.DEFAULT_MATCHING_STRATEGY.value)) self._matching_strategy_combo_box = QComboBox(self) self._matching_strategy_combo_box.addItems( [x.value for x in NappingDialog.MatchingStrategy]) self._matching_strategy_combo_box.setCurrentText( matching_strategy_combo_box_current_text) # noinspection PyUnresolvedReferences self._matching_strategy_combo_box.currentIndexChanged.connect( lambda _: self.refresh()) source_images_file_line_edit_text = str( settings.value(self.SOURCE_IMAGES_SETTING, defaultValue=self.DEFAULT_SOURCE_IMAGES)) self._source_images_file_line_edit = FileLineEdit(check_exists=True, parent=self) self._source_images_file_line_edit.file_dialog.setWindowTitle( 'Select source image(s)') self._source_images_file_line_edit.setText( source_images_file_line_edit_text) # noinspection PyUnresolvedReferences self._source_images_file_line_edit.textChanged.connect( lambda text: self.refresh(text)) source_regex_line_edit_text = str( settings.value(self.SOURCE_REGEX_SETTING, defaultValue=self.DEFAULT_SOURCE_REGEX)) self._source_regex_label = QLabel(' RegEx:') self._source_regex_line_edit = QLineEdit(self) self._source_regex_line_edit.setText(source_regex_line_edit_text) # noinspection PyUnresolvedReferences self._source_regex_line_edit.textChanged.connect( lambda _: self.refresh()) target_images_file_line_edit_text = str( settings.value(self.TARGET_IMAGES_SETTING, defaultValue=self.DEFAULT_TARGET_IMAGES)) self._target_images_file_line_edit = FileLineEdit(check_exists=True, parent=self) self._target_images_file_line_edit.file_dialog.setWindowTitle( 'Select target image(s)') self._target_images_file_line_edit.setText( target_images_file_line_edit_text) # noinspection PyUnresolvedReferences self._target_images_file_line_edit.textChanged.connect( lambda text: self.refresh(text)) target_regex_line_edit_text = str( settings.value(self.TARGET_REGEX_SETTING, defaultValue=self.DEFAULT_TARGET_REGEX)) self._target_regex_label = QLabel(' RegEx:') self._target_regex_line_edit = QLineEdit(self) self._target_regex_line_edit.setText(target_regex_line_edit_text) # noinspection PyUnresolvedReferences self._target_regex_line_edit.textChanged.connect( lambda _: self.refresh()) control_points_dest_file_line_edit_text = str( settings.value(self.CONTROL_POINTS_DEST_SETTING, defaultValue=self.DEFAULT_CONTROL_POINTS_DEST)) self._control_points_dest_file_line_edit = FileLineEdit(parent=self) self._control_points_dest_file_line_edit.file_dialog.setWindowTitle( 'Select control points destination') self._control_points_dest_file_line_edit.setText( control_points_dest_file_line_edit_text) # noinspection PyUnresolvedReferences self._control_points_dest_file_line_edit.textChanged.connect( lambda text: self.refresh(text)) joint_transform_dest_file_line_edit_text = str( settings.value(self.JOINT_TRANSFORM_DEST_SETTING, defaultValue=self.DEFAULT_JOINT_TRANSFORM_DEST)) self._joint_transform_dest_file_line_edit = FileLineEdit(parent=self) self._joint_transform_dest_file_line_edit.file_dialog.setWindowTitle( 'Select joint transform destination') self._joint_transform_dest_file_line_edit.setText( joint_transform_dest_file_line_edit_text) # noinspection PyUnresolvedReferences self._joint_transform_dest_file_line_edit.textChanged.connect( lambda text: self.refresh(text)) transform_type_combo_box_current_text = str( settings.value(self.TRANSFORM_TYPE_SETTING, defaultValue=self.DEFAULT_TRANSFORM_TYPE)) self._transform_type_combo_box = QComboBox(self) self._transform_type_combo_box.addItems( [x.value for x in NappingDialog.TransformType]) self._transform_type_combo_box.setCurrentText( transform_type_combo_box_current_text) # noinspection PyUnresolvedReferences self._transform_type_combo_box.currentIndexChanged.connect( lambda _: self.refresh()) source_coords_file_line_edit_text = str( settings.value(self.SOURCE_COORDS_SETTING, defaultValue=self.DEFAULT_SOURCE_COORDS)) self._source_coords_file_line_edit = FileLineEdit(check_exists=True, parent=self) self._source_coords_file_line_edit.file_dialog.setWindowTitle( 'Select source coordinates') self._source_coords_file_line_edit.setText( source_coords_file_line_edit_text) # noinspection PyUnresolvedReferences self._source_coords_file_line_edit.textChanged.connect( lambda text: self.refresh(text)) source_coords_regex_line_edit_text = str( settings.value(self.SOURCE_COORDS_REGEX_SETTING, defaultValue=self.DEFAULT_SOURCE_COORDS_REGEX)) self._source_coords_regex_label = QLabel(' RegEx:') self._source_coords_regex_line_edit = QLineEdit(self) self._source_coords_regex_line_edit.setText( source_coords_regex_line_edit_text) # noinspection PyUnresolvedReferences self._source_coords_regex_line_edit.textChanged.connect( lambda _: self.refresh()) transformed_coords_dest_file_line_edit_text = str( settings.value(self.TRANSFORMED_COORDS_DEST_SETTING, defaultValue=self.DEFAULT_TRANSFORMED_COORDS_DEST)) self._transformed_coords_dest_file_line_edit = FileLineEdit( parent=self) self._transformed_coords_dest_file_line_edit.file_dialog.setWindowTitle( 'Select transformed coordinates destination') self._transformed_coords_dest_file_line_edit.setText( transformed_coords_dest_file_line_edit_text) # noinspection PyUnresolvedReferences self._transformed_coords_dest_file_line_edit.textChanged.connect( lambda text: self.refresh(text)) pre_transform_file_line_edit_text = str( settings.value(self.PRE_TRANSFORM_SETTING, defaultValue=self.DEFAULT_PRE_TRANSFORM)) self._pre_transform_file_line_edit = FileLineEdit(parent=self) self._pre_transform_file_line_edit.file_dialog.setWindowTitle( 'Select pre-transform') self._pre_transform_file_line_edit.setText( pre_transform_file_line_edit_text) self._pre_transform_file_line_edit.file_dialog.setFileMode( QFileDialog.ExistingFile) self._pre_transform_file_line_edit.file_dialog.setNameFilter( 'Numpy files (*.npy)') # noinspection PyUnresolvedReferences self._pre_transform_file_line_edit.textChanged.connect( lambda text: self.refresh(text)) post_transform_file_line_edit_text = str( settings.value(self.POST_TRANSFORM_SETTING, defaultValue=self.DEFAULT_POST_TRANSFORM)) self._post_transform_file_line_edit = FileLineEdit(parent=self) self._post_transform_file_line_edit.file_dialog.setWindowTitle( 'Select post-transform') self._post_transform_file_line_edit.file_dialog.setFileMode( QFileDialog.ExistingFile) self._post_transform_file_line_edit.file_dialog.setNameFilter( 'Numpy files (*.npy)') self._post_transform_file_line_edit.setText( post_transform_file_line_edit_text) # noinspection PyUnresolvedReferences self._post_transform_file_line_edit.textChanged.connect( lambda text: self.refresh(text)) self._button_box = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self) # noinspection PyUnresolvedReferences self._button_box.rejected.connect(self.reject) # noinspection PyUnresolvedReferences @self._button_box.accepted.connect def on_button_box_accepted(): settings.setValue(self.SELECTION_MODE_SETTING, self.selection_mode.value) settings.setValue(self.SOURCE_IMAGES_SETTING, str(self.source_images_path)) settings.setValue(self.SOURCE_REGEX_SETTING, self.source_regex) settings.setValue(self.TARGET_IMAGES_SETTING, str(self.target_images_path)) settings.setValue(self.TARGET_REGEX_SETTING, self.target_regex) settings.setValue(self.CONTROL_POINTS_DEST_SETTING, str(self.control_points_dest_path)) settings.setValue(self.JOINT_TRANSFORM_DEST_SETTING, str(self.joint_transform_dest_path)) settings.setValue(self.TRANSFORM_TYPE_SETTING, self.transform_type.value) settings.setValue(self.MATCHING_STRATEGY_SETTING, self.matching_strategy.value) settings.setValue(self.SOURCE_COORDS_SETTING, str(self.source_coords_path or '')) settings.setValue(self.SOURCE_COORDS_REGEX_SETTING, self.source_coords_regex) settings.setValue(self.TRANSFORMED_COORDS_DEST_SETTING, str(self.transformed_coords_dest_path or '')) settings.setValue(self.PRE_TRANSFORM_SETTING, str(self.pre_transform_path or '')) settings.setValue(self.POST_TRANSFORM_SETTING, str(self.post_transform_path or '')) settings.sync() self.accept() required_group_box = QGroupBox(self) required_group_box_layout = QFormLayout() required_group_box_layout.setLabelAlignment(Qt.AlignLeft) required_group_box_layout.setRowWrapPolicy(QFormLayout.DontWrapRows) required_group_box_layout.setFieldGrowthPolicy( QFormLayout.AllNonFixedFieldsGrow) required_group_box_layout.addRow('Source image(s):', self._source_images_file_line_edit) required_group_box_layout.addRow(self._source_regex_label, self._source_regex_line_edit) required_group_box_layout.addRow('Target image(s):', self._target_images_file_line_edit) required_group_box_layout.addRow(self._target_regex_label, self._target_regex_line_edit) required_group_box_layout.addRow( 'Control points dest.:', self._control_points_dest_file_line_edit) required_group_box_layout.addRow( 'Joint transform dest.:', self._joint_transform_dest_file_line_edit) required_group_box_layout.addRow('Transform type:', self._transform_type_combo_box) required_group_box.setLayout(required_group_box_layout) optional_group_box = QGroupBox(self) optional_group_box_layout = QFormLayout() optional_group_box_layout.setLabelAlignment(Qt.AlignLeft) optional_group_box_layout.setRowWrapPolicy(QFormLayout.DontWrapRows) optional_group_box_layout.setFieldGrowthPolicy( QFormLayout.AllNonFixedFieldsGrow) optional_group_box_layout.addRow('Source coordinates:', self._source_coords_file_line_edit) optional_group_box_layout.addRow(self._source_coords_regex_label, self._source_coords_regex_line_edit) optional_group_box_layout.addRow( 'Transformed coord. dest.:', self._transformed_coords_dest_file_line_edit) optional_group_box_layout.addRow('Pre-transform:', self._pre_transform_file_line_edit) optional_group_box_layout.addRow('Post-transform:', self._post_transform_file_line_edit) optional_group_box.setLayout(optional_group_box_layout) layout = QVBoxLayout() mode_layout = QHBoxLayout() # noinspection PyArgumentList mode_layout.addWidget(self._file_selection_mode_button) # noinspection PyArgumentList mode_layout.addWidget(self._dir_selection_mode_button) # noinspection PyArgumentList mode_layout.addWidget(self._matching_strategy_combo_box) mode_layout.addStretch() layout.addLayout(mode_layout) # noinspection PyArgumentList layout.addWidget(required_group_box) # noinspection PyArgumentList layout.addWidget(optional_group_box) # noinspection PyArgumentList layout.addWidget(self._button_box) self.setLayout(layout) self.setWindowTitle('Control point matching') self.setMinimumWidth(600) self.refresh() @property def selection_mode(self) -> Optional['NappingDialog.SelectionMode']: selection_mode_value = self._selection_mode_buttons_group.checkedId() if selection_mode_value >= 0: return NappingDialog.SelectionMode(selection_mode_value) return None @property def matching_strategy(self) -> 'NappingDialog.MatchingStrategy': return NappingDialog.MatchingStrategy( self._matching_strategy_combo_box.currentText()) @property def source_images_path(self) -> Optional[Path]: return self._source_images_file_line_edit.path @property def source_regex(self) -> str: return self._source_regex_line_edit.text() @property def target_images_path(self) -> Optional[Path]: return self._target_images_file_line_edit.path @property def target_regex(self) -> str: return self._target_regex_line_edit.text() @property def control_points_dest_path(self) -> Optional[Path]: return self._control_points_dest_file_line_edit.path @property def joint_transform_dest_path(self) -> Optional[Path]: return self._joint_transform_dest_file_line_edit.path @property def transform_type(self) -> 'NappingDialog.TransformType': return NappingDialog.TransformType( self._transform_type_combo_box.currentText()) @property def transform_class(self) -> Type[ProjectiveTransform]: return { NappingDialog.TransformType.EUCLIDEAN: EuclideanTransform, NappingDialog.TransformType.SIMILARITY: SimilarityTransform, NappingDialog.TransformType.AFFINE: AffineTransform }[self.transform_type] @property def source_coords_path(self) -> Optional[Path]: return self._source_coords_file_line_edit.path @property def source_coords_regex(self) -> str: return self._source_coords_regex_line_edit.text() @property def transformed_coords_dest_path(self) -> Optional[Path]: return self._transformed_coords_dest_file_line_edit.path @property def pre_transform_path(self) -> Optional[Path]: return self._pre_transform_file_line_edit.path @property def post_transform_path(self) -> Optional[Path]: return self._post_transform_file_line_edit.path @property def is_valid(self) -> bool: if self.selection_mode == NappingDialog.SelectionMode.FILE: if self.source_images_path is None or not self.source_images_path.is_file( ): return False if self.target_images_path is None or not self.target_images_path.is_file( ): return False if self.control_points_dest_path is None or self.control_points_dest_path.is_dir( ): return False if self.joint_transform_dest_path is None or self.joint_transform_dest_path.is_dir( ): return False if self.source_coords_path is not None and not self.source_coords_path.is_file( ): return False if self.transformed_coords_dest_path is not None and self.control_points_dest_path.is_dir( ): return False elif self.selection_mode == NappingDialog.SelectionMode.DIR: if self.source_images_path is None or not self.source_images_path.is_dir( ): return False if self.target_images_path is None or not self.target_images_path.is_dir( ): return False if self.control_points_dest_path is None or self.control_points_dest_path.is_file( ): return False if self.joint_transform_dest_path is None or self.joint_transform_dest_path.is_file( ): return False if self.source_coords_path is not None and not self.source_coords_path.is_dir( ): return False if self.transformed_coords_dest_path is not None and self.control_points_dest_path.is_file( ): return False if self.matching_strategy == NappingDialog.MatchingStrategy.REGEX: if not self.source_regex: return False if not self.target_regex: return False if self.source_coords_path is not None and not self.source_coords_regex: return False else: return False if self.pre_transform_path is not None and not self.pre_transform_path.is_file( ): return False if self.post_transform_path is not None and not self.post_transform_path.is_file( ): return False if bool(self.source_coords_path) != bool( self.transformed_coords_dest_path): return False if (bool(self.pre_transform_path) or bool(self.post_transform_path) ) and not bool(self.source_coords_path): return False unique_paths = { self.source_images_path, self.target_images_path, self.control_points_dest_path, self.joint_transform_dest_path } if self.source_coords_path is not None and self.transformed_coords_dest_path is not None: unique_paths.update( {self.source_coords_path, self.transformed_coords_dest_path}) if len(unique_paths) != 6: return False elif len(unique_paths) != 4: return False return True def refresh(self, last_path: Union[str, Path, None] = None): if last_path: directory = str(Path(last_path).parent) self._source_images_file_line_edit.file_dialog.setDirectory( directory) self._target_images_file_line_edit.file_dialog.setDirectory( directory) self._control_points_dest_file_line_edit.file_dialog.setDirectory( directory) self._joint_transform_dest_file_line_edit.file_dialog.setDirectory( directory) self._source_coords_file_line_edit.file_dialog.setDirectory( directory) self._transformed_coords_dest_file_line_edit.file_dialog.setDirectory( directory) self._pre_transform_file_line_edit.file_dialog.setDirectory( directory) self._post_transform_file_line_edit.file_dialog.setDirectory( directory) if self.selection_mode in (NappingDialog.SelectionMode.FILE, NappingDialog.SelectionMode.DIR): if self.selection_mode == NappingDialog.SelectionMode.FILE: any_file_mode = QFileDialog.AnyFile existing_file_mode = QFileDialog.ExistingFile control_points_name_filter = 'CSV files (*.csv)' control_points_default_suffix = '.csv' transform_name_filter = 'Numpy files (*.npy)' transform_default_suffix = '.npy' source_coords_name_filter = transformed_coords_name_filter = 'CSV files (*.csv)' source_coords_default_suffix = transformed_coords_default_suffix = '.csv' show_dirs_only = False else: any_file_mode = QFileDialog.Directory existing_file_mode = QFileDialog.Directory control_points_name_filter = None control_points_default_suffix = None transform_name_filter = None transform_default_suffix = None source_coords_name_filter = transformed_coords_name_filter = None source_coords_default_suffix = transformed_coords_default_suffix = None show_dirs_only = True self._source_images_file_line_edit.file_dialog.setFileMode( existing_file_mode) self._source_images_file_line_edit.file_dialog.setOption( QFileDialog.ShowDirsOnly, show_dirs_only) self._target_images_file_line_edit.file_dialog.setFileMode( existing_file_mode) self._target_images_file_line_edit.file_dialog.setOption( QFileDialog.ShowDirsOnly, show_dirs_only) self._control_points_dest_file_line_edit.file_dialog.setFileMode( any_file_mode) self._control_points_dest_file_line_edit.file_dialog.setNameFilter( control_points_name_filter) self._control_points_dest_file_line_edit.file_dialog.setDefaultSuffix( control_points_default_suffix) self._control_points_dest_file_line_edit.file_dialog.setOption( QFileDialog.ShowDirsOnly, show_dirs_only) self._joint_transform_dest_file_line_edit.file_dialog.setFileMode( any_file_mode) self._joint_transform_dest_file_line_edit.file_dialog.setNameFilter( transform_name_filter) self._joint_transform_dest_file_line_edit.file_dialog.setDefaultSuffix( transform_default_suffix) self._joint_transform_dest_file_line_edit.file_dialog.setOption( QFileDialog.ShowDirsOnly, show_dirs_only) self._source_coords_file_line_edit.file_dialog.setFileMode( existing_file_mode) self._source_coords_file_line_edit.file_dialog.setNameFilter( source_coords_name_filter) self._source_coords_file_line_edit.file_dialog.setDefaultSuffix( source_coords_default_suffix) self._source_coords_file_line_edit.file_dialog.setOption( QFileDialog.ShowDirsOnly, show_dirs_only) self._transformed_coords_dest_file_line_edit.file_dialog.setFileMode( any_file_mode) self._transformed_coords_dest_file_line_edit.file_dialog.setNameFilter( transformed_coords_name_filter) self._transformed_coords_dest_file_line_edit.file_dialog.setDefaultSuffix( transformed_coords_default_suffix) self._transformed_coords_dest_file_line_edit.file_dialog.setOption( QFileDialog.ShowDirsOnly, show_dirs_only) if self.selection_mode == NappingDialog.SelectionMode.DIR: self._matching_strategy_combo_box.setEnabled(True) else: self._matching_strategy_combo_box.setEnabled(False) dir_selection_mode = ( self.selection_mode == NappingDialog.SelectionMode.DIR) regex_matching_strategy = ( self.matching_strategy == NappingDialog.MatchingStrategy.REGEX) self._source_regex_label.setEnabled(dir_selection_mode and regex_matching_strategy) self._source_regex_line_edit.setEnabled(dir_selection_mode and regex_matching_strategy) self._target_regex_label.setEnabled(dir_selection_mode and regex_matching_strategy) self._target_regex_line_edit.setEnabled(dir_selection_mode and regex_matching_strategy) self._source_coords_regex_label.setEnabled(dir_selection_mode and regex_matching_strategy) self._source_coords_regex_line_edit.setEnabled( dir_selection_mode and regex_matching_strategy) self._button_box.button(QDialogButtonBox.Ok).setEnabled(self.is_valid)