class PreferencesDialog(QtWidgets.QDialog): def __init__(self, parent, cmdp): QtWidgets.QDialog.__init__(self, parent) self._active_group = None self._active_profile = cmdp.preferences.profile self._params = [] self._cmdp = cmdp self.ui = Ui_PreferencesDialog() self.ui.setupUi(self) self._definitions = self._cmdp.preferences.definitions if self._definitions['name'] != '/': raise ValueError('unexpected root') self._definitions_tree_map = {} self._tree_model = QtGui.QStandardItemModel(self) self._tree_model.setHorizontalHeaderLabels(['Name']) self.ui.treeView.setModel(self._tree_model) self.ui.treeView.setHeaderHidden(True) self.ui.treeView.selectionModel().currentChanged.connect(self._on_tree_item_changed) self._tree_populate(self._tree_model.invisibleRootItem(), self._definitions) select_mode_index = self._tree_model.index(0, 0) self.ui.treeView.setCurrentIndex(select_mode_index) self.ui.treeView.expandAll() self._on_tree_item_changed(select_mode_index, None) self.ui.profileComboBox.currentIndexChanged.connect(self._on_profile_combo_box_change) self._profile_combobox_update() self.ui.profileActivateButton.pressed.connect(self._on_profile_activate_button) self.ui.profileResetButton.pressed.connect(self._on_profile_reset_button) self.ui.profileNewButton.pressed.connect(self._on_profile_new_button) self.ui.helpButton.pressed.connect(self._help) self.ui.okButton.pressed.connect(self.accept) self.ui.cancelButton.pressed.connect(self.reject) self.ui.resetButton.pressed.connect(self.preferences_reset) self._cmdp.subscribe('!preferences/profile/add', self._on_profile_add) self._cmdp.subscribe('!preferences/profile/remove', self._on_profile_remove) self._refresh_topic = f'!preferences/_ui/refresh_{id(self)}' self._cmdp.register(self._refresh_topic, self._refresh) def _help(self): display_help(self, 'preferences') def _refresh(self, topic, value): self._redraw_right_pane() def _on_profile_combo_box_change(self, index): profile = self.ui.profileComboBox.currentText() self._profile_change(profile) def _on_profile_add(self, topic, data): log.info('_on_profile_add(%s) %s', data, self._active_profile) self._profile_change(data) def _on_profile_remove(self, topic, data): log.info('_on_profile_remove(%s) : %s', data, self._active_profile) if data == self._active_profile: self._profile_change() def _profile_change(self, profile=None): if profile is None: profile = self._cmdp.preferences.profile if profile == self._active_profile: return if profile != self._active_profile: self._active_profile = profile self._profile_combobox_update() self._redraw_right_pane() def _on_profile_activate_button(self): self._cmdp.invoke('!preferences/profile/set', self._active_profile) self.ui.profileActivateButton.setEnabled(False) def _on_profile_reset_button(self): self._profile_reset() def _profile_reset(self, prefix=''): log.info('profile_reset start %s : %s', self._active_profile, prefix) existing = self._cmdp.preferences.state_export()['profiles'][self._active_profile] if self._active_profile in preferences_defaults.PROFILES_RESET: default_profile = preferences_defaults.Preferences(app='joulescope_config') preferences_defaults.defaults(default_profile) defaults = default_profile.state_export()['profiles'][self._active_profile] else: defaults = {} for key, new_value in defaults.items(): if key.startswith(prefix): existing.pop(key, None) # remove if possible self._cmdp.invoke('!preferences/preference/set', (key, new_value, self._active_profile)) for key, old_value in existing.items(): if '#' in key or key[-1] == '/' or '/_' in key: continue if key.startswith(prefix): self._cmdp.invoke('!preferences/preference/clear', (key, self._active_profile)) # special case state preferences if prefix == '' or prefix == 'General': self._cmdp.invoke('!preferences/preference/set', ('_window', None, self._active_profile)) self._cmdp.invoke(self._refresh_topic, None) log.info('profile_reset done %s : %s', self._active_profile, prefix) def _on_profile_new_button(self): profile, success = QtWidgets.QInputDialog.getText(self, 'Enter profile name', 'Profile Name:') if not success: return if profile in self._cmdp.preferences.profiles: log.warning('Already exists - switch to it') self._cmdp.invoke('!preferences/profile/set', profile) else: self._cmdp.invoke('!preferences/profile/add', profile) self._redraw_right_pane() def _profile_combobox_update(self): if self._active_profile not in self._cmdp.preferences.profiles: self._active_profile = self._cmdp.preferences.profile comboBoxConfig(self.ui.profileComboBox, self._cmdp.preferences.profiles, self._active_profile) reset_text = 'Reset' if self._active_profile in preferences_defaults.PROFILES_RESET else 'Erase' self.ui.profileResetButton.setText(reset_text) self.ui.profileActivateButton.setEnabled(self._active_profile != self._cmdp.preferences.profile) def _tree_populate(self, parent, d): if 'children' not in d: return for name, child in d['children'].items(): definition_name = child['name'] if '#' in name or name.startswith('_') or not child['name'].endswith('/'): continue child_children = [x for x in child.get('children', {}).keys() if '#' not in x and not x.startswith('_')] if not len(child_children): continue child_item = QtGui.QStandardItem(name) # WARNING: setData with dict causes key reordering. Store str and lookup. self._definitions_tree_map[definition_name] = child child_item.setData(definition_name, QtCore.Qt.UserRole + 1) parent.appendRow(child_item) self._tree_populate(child_item, child) def _clear(self): if self._active_group is not None: for param in self._params: param.unpopulate(self.ui.targetWidget) self._params = [] self._active_group = None @QtCore.Slot(object, object) def _on_tree_item_changed(self, model_index, model_index_old): self._clear() definition_name = self._tree_model.data(model_index, QtCore.Qt.UserRole + 1) data = self._definitions_tree_map[definition_name] self._populate_selected(data) def _populate_selected(self, data): if 'children' not in data: return self._active_group = data['name'] for name, child in data['children'].items(): if 'children' in child: continue if '#' in name or name.startswith('_') or child['name'].endswith('/'): continue self._populate_entry(name, child) def _populate_entry(self, name, entry): p = widget_factory(self._cmdp, entry['name'], profile=self._active_profile) if p is not None: p.populate(self.ui.targetWidget) self._params.append(p) def preferences_reset(self): self._profile_reset(self._active_group) def exec_(self): self._cmdp.invoke('!command_group/start') rv = QtWidgets.QDialog.exec_(self) self._cmdp.invoke('!command_group/end') self._clear() if rv == 0: self._cmdp.invoke('!undo') return rv def _redraw_right_pane(self): self._clear() self._on_tree_item_changed(self.ui.treeView.currentIndex(), None)
class PreferencesDialog(QtWidgets.QDialog): def __init__(self, parent, cmdp): QtWidgets.QDialog.__init__(self, parent) self._active_group = None self._active_profile = cmdp.preferences.profile self._params = [] self._cmdp = cmdp self.ui = Ui_PreferencesDialog() self.ui.setupUi(self) self._definitions = self._cmdp.preferences.definitions if self._definitions['name'] != '/': raise ValueError('unexpected root') self._definitions_tree_map = {} self._tree_model = QtGui.QStandardItemModel(self) self._tree_model.setHorizontalHeaderLabels(['Name']) self.ui.treeView.setModel(self._tree_model) self.ui.treeView.setHeaderHidden(True) self.ui.treeView.selectionModel().currentChanged.connect( self._on_tree_item_changed) self._tree_populate(self._tree_model.invisibleRootItem(), self._definitions) select_mode_index = self._tree_model.index(0, 0) self.ui.treeView.setCurrentIndex(select_mode_index) self.ui.treeView.expandAll() self._on_tree_item_changed(select_mode_index, None) self.ui.profileComboBox.currentIndexChanged.connect( self._on_profile_combo_box_change) self._profile_combobox_update() self.ui.profileActivateButton.pressed.connect( self._on_profile_activate_button) self.ui.profileResetButton.pressed.connect( self._on_profile_reset_button) self.ui.profileNewButton.pressed.connect(self._on_profile_new_button) self.ui.okButton.pressed.connect(self.accept) self.ui.cancelButton.pressed.connect(self.reject) self.ui.resetButton.pressed.connect(self.preferences_reset) self._cmdp.subscribe('!preferences/profile/add', self._on_profile_add) self._cmdp.subscribe('!preferences/profile/remove', self._on_profile_remove) def _on_profile_combo_box_change(self, index): profile = self.ui.profileComboBox.currentText() self._profile_change(profile) def _on_profile_add(self, topic, data): log.info('_on_profile_add(%s) %s', data, self._active_profile) self._profile_change(data) def _on_profile_remove(self, topic, data): log.info('_on_profile_remove(%s) : %s', data, self._active_profile) if data == self._active_profile: self._profile_change() def _profile_change(self, profile=None): if profile is None: profile = self._cmdp.preferences.profile if profile == self._active_profile: return if profile != self._active_profile: self._active_profile = profile self._profile_combobox_update() self._on_tree_item_changed(self.ui.treeView.currentIndex(), None) def _on_profile_activate_button(self): self._cmdp.invoke('!preferences/profile/set', self._active_profile) self.ui.profileActivateButton.setEnabled(False) def _on_profile_reset_button(self): if self._active_profile in preferences_defaults.PROFILES_RESET: preferences_defaults.restore(self._cmdp.preferences, self._active_profile) else: self._cmdp.invoke('!preferences/profile/remove', self._active_profile) def _on_profile_new_button(self): profile, success = QtWidgets.QInputDialog.getText( self, 'Enter profile name', 'Profile Name:') if not success: return if profile in self._cmdp.preferences.profiles: log.warning('Already exists - switch to it') self._cmdp.invoke('!preferences/profile/set', profile) else: self._cmdp.invoke('!preferences/profile/add', profile) def _profile_combobox_update(self): if self._active_profile not in self._cmdp.preferences.profiles: self._active_profile = self._cmdp.preferences.profile comboBoxConfig(self.ui.profileComboBox, self._cmdp.preferences.profiles, self._active_profile) reset_text = 'Reset' if self._active_profile in preferences_defaults.PROFILES_RESET else 'Erase' self.ui.profileResetButton.setText(reset_text) self.ui.profileActivateButton.setEnabled( self._active_profile != self._cmdp.preferences.profile) def _tree_populate(self, parent, d): if 'children' not in d: return for name, child in d['children'].items(): definition_name = child['name'] if '#' in name or name.startswith( '_') or not child['name'].endswith('/'): continue child_children = [ x for x in child.get('children', {}).keys() if '#' not in x and not x.startswith('_') ] if not len(child_children): continue child_item = QtGui.QStandardItem(name) # WARNING: setData with dict causes key reordering. Store str and lookup. self._definitions_tree_map[definition_name] = child child_item.setData(definition_name, QtCore.Qt.UserRole + 1) parent.appendRow(child_item) self._tree_populate(child_item, child) def _clear(self): if self._active_group is not None: for param in self._params: param.unpopulate(self.ui.targetWidget) self._params = [] self._active_group = None @QtCore.Slot(object, object) def _on_tree_item_changed(self, model_index, model_index_old): self._clear() definition_name = self._tree_model.data(model_index, QtCore.Qt.UserRole + 1) data = self._definitions_tree_map[definition_name] self._populate_selected(data) def _populate_selected(self, data): if 'children' not in data: return self._active_group = data['name'] for name, child in data['children'].items(): if 'children' in child: continue if '#' in name or name.startswith('_') or child['name'].endswith( '/'): continue self._populate_entry(name, child) def _populate_entry(self, name, entry): p = widget_factory(self._cmdp, entry['name'], profile=self._active_profile) if p is not None: p.populate(self.ui.targetWidget) self._params.append(p) def on_selection_change(self, selection): log.info('on_selection_change(%r)', selection) model_index_list = selection.indexes() if len(model_index_list) != 1: # force the first item self.ui.groupListView.setCurrentIndex(self._model.item(0).index()) return self._clear() name = model_index_list[0].data() self._populate(name) def preferences_reset(self): active_group = self._active_group self._clear() self._populate(active_group) def exec_(self): self._cmdp.invoke('!command_group/start') rv = QtWidgets.QDialog.exec_(self) self._cmdp.invoke('!command_group/end') if rv == 0: self._cmdp.invoke('!undo')
class PreferencesDialog(QtWidgets.QDialog): def __init__(self, cfg_def, cfg): QtWidgets.QDialog.__init__(self) self._active_group = None self._params = [] self._cfg_def = cfg_def self.cfg_orig = cfg self._cfg = copy.deepcopy(cfg) self.ui = Ui_PreferencesDialog() self.ui.setupUi(self) self._model = QtGui.QStandardItemModel() for entry in self._cfg_def['children']: item = QtGui.QStandardItem(entry['name']) self._model.appendRow(item) self.ui.groupListView.setModel(self._model) self.ui.groupListView.selectionModel().selectionChanged.connect( self.on_selection_change) self.ui.groupListView.setCurrentIndex(self._model.item(0).index()) self.ui.okButton.pressed.connect(self.accept) self.ui.cancelButton.pressed.connect(self.cancel) self.ui.resetButton.pressed.connect(self.cfg_reset) def update(self): if self._active_group is None: return for param in self._params: self._cfg[self._active_group][param.name] = param.value def _clear(self): if self._active_group is not None: for param in self._params: param.unpopulate(self.ui.targetWidget) self._params = [] self._active_group = None def _populate(self, group_name: str): group = find_child_by_name(self._cfg_def, group_name) if group is None: return self._active_group = group_name for entry in group['children']: name = entry['name'] value = self._cfg[self._active_group][name] p = None tooltip = '' if 'brief' in entry: tooltip = '<span><p>%s</p>' % entry['brief'] if 'detail' in entry: tooltip += '<p>%s</p>' % entry['detail'] tooltip += '</span>' if entry['type'] == 'str' and 'options' in entry: options = [x['name'] for x in entry['options']] p = guiparams.Enum(name, value, options, tooltip=tooltip) elif entry['type'] == 'bool': if isinstance(value, str): value = value.lower() value = value in [True, 'true', 'on'] p = guiparams.Bool(name, value, tooltip=tooltip) elif entry['type'] == 'path': attributes = entry.get('attributes', []) if 'dir' in attributes: p = guiparams.Directory(name, value, tooltip=tooltip) elif 'exists' in attributes: p = guiparams.FileOpen(name, value, tooltip=tooltip) else: p = guiparams.FileSave(name, value, tooltip=tooltip) if p is not None: p.populate(self.ui.targetWidget) self._params.append(p) def on_selection_change(self, selection): log.info('on_selection_change(%r)', selection) model_index_list = selection.indexes() if len(model_index_list) != 1: # force the first item self.ui.groupListView.setCurrentIndex(self._model.item(0).index()) return self.update() self._clear() name = model_index_list[0].data() self._populate(name) def cancel(self): self.update() if self.cfg_orig == self._cfg: QtWidgets.QDialog.reject(self) elif confirmDiscard(self): QtWidgets.QDialog.reject(self) def cfg_reset(self): active_group = self._active_group self._clear() self._cfg = validate(self._cfg_def, {}) self._populate(active_group) def exec_(self): if QtWidgets.QDialog.exec_(self) == 1: self.update() return self._cfg # accepted! return None