class OWEditDomain(widget.OWWidget): name = "Edit Domain" description = "Rename features and their values." icon = "icons/EditDomain.svg" priority = 3125 inputs = [("Data", Orange.data.Table, "set_data")] outputs = [("Data", Orange.data.Table)] settingsHandler = settings.DomainContextHandler() domain_change_hints = settings.ContextSetting({}) selected_index = settings.ContextSetting({}) autocommit = settings.Setting(False) def __init__(self): super().__init__() self.data = None self.input_vars = () self._invalidated = False box = gui.vBox(self.controlArea, "Domain Features") self.domain_model = itemmodels.VariableListModel() self.domain_view = QListView( selectionMode=QListView.SingleSelection ) self.domain_view.setModel(self.domain_model) self.domain_view.selectionModel().selectionChanged.connect( self._on_selection_changed) box.layout().addWidget(self.domain_view) box = gui.hBox(self.controlArea) gui.button(box, self, "Reset Selected", callback=self.reset_selected) gui.button(box, self, "Reset All", callback=self.reset_all) gui.auto_commit(self.controlArea, self, "autocommit", "Apply") box = gui.vBox(self.mainArea, "Edit") self.editor_stack = QStackedWidget() self.editor_stack.addWidget(DiscreteVariableEditor()) self.editor_stack.addWidget(ContinuousVariableEditor()) self.editor_stack.addWidget(VariableEditor()) box.layout().addWidget(self.editor_stack) @check_sql_input def set_data(self, data): """Set input data set.""" self.closeContext() self.clear() self.data = data if self.data is not None: self._initialize() self.openContext(self.data) self._restore() self.unconditional_commit() def clear(self): """Clear the widget state.""" self.data = None self.domain_model[:] = [] self.input_vars = [] self.domain_change_hints = {} self.selected_index = -1 def reset_selected(self): """Reset the currently selected variable to its original state.""" ind = self.selected_var_index() if ind >= 0: var = self.input_vars[ind] desc = variable_description(var, skip_attributes=True) if desc in self.domain_change_hints: del self.domain_change_hints[desc] self.domain_model[ind] = var self.editor_stack.currentWidget().set_data(var) self._invalidate() def reset_all(self): """Reset all variables to their original state.""" self.domain_change_hints = {} if self.data is not None: # To invalidate stored hints self.domain_model[:] = self.input_vars itemmodels.select_row(self.domain_view, self.selected_index) self._invalidate() def selected_var_index(self): """Return the selected row in 'Domain Features' view.""" rows = self.domain_view.selectedIndexes() assert len(rows) <= 1 return rows[0].row() if rows else -1 def _initialize(self): domain = self.data.domain self.input_vars = tuple(domain) + domain.metas self.domain_model[:] = list(self.input_vars) def _restore(self): # Restore the variable states from saved settings. def transform(var): vdesc = variable_description(var, skip_attributes=True) if vdesc in self.domain_change_hints: return variable_from_description( self.domain_change_hints[vdesc], compute_value=Orange.preprocess.transformation.Identity(var)) else: return var self.domain_model[:] = map(transform, self.input_vars) # Restore the variable selection if possible index = self.selected_index if index >= len(self.input_vars): index = 0 if len(self.input_vars) else -1 if index >= 0: itemmodels.select_row(self.domain_view, index) def _on_selection_changed(self): self.selected_index = self.selected_var_index() self.open_editor(self.selected_index) def open_editor(self, index): self.clear_editor() if index < 0: return var = self.domain_model[index] editor_index = 2 if var.is_discrete: editor_index = 0 elif var.is_continuous: editor_index = 1 editor = self.editor_stack.widget(editor_index) self.editor_stack.setCurrentWidget(editor) editor.set_data(var) editor.variable_changed.connect(self._on_variable_changed) def clear_editor(self): current = self.editor_stack.currentWidget() try: current.variable_changed.disconnect(self._on_variable_changed) except Exception: pass current.set_data(None) def _on_variable_changed(self): """User edited the current variable in editor.""" assert 0 <= self.selected_index <= len(self.domain_model) editor = self.editor_stack.currentWidget() # Replace the variable in the 'Domain Features' view/model old_var = self.input_vars[self.selected_index] new_var = editor.get_data().copy(compute_value=Orange.preprocess.transformation.Identity(old_var)) self.domain_model[self.selected_index] = new_var # Store the transformation hint. old_var_desc = variable_description(old_var, skip_attributes=True) self.domain_change_hints[old_var_desc] = variable_description(new_var) self._invalidate() def _invalidate(self): self.commit() def commit(self): """Send the changed data to output.""" new_data = None if self.data is not None: input_domain = self.data.domain n_attrs = len(input_domain.attributes) n_vars = len(input_domain.variables) n_class_vars = len(input_domain.class_vars) all_new_vars = list(self.domain_model) attrs = all_new_vars[: n_attrs] class_vars = all_new_vars[n_attrs: n_attrs + n_class_vars] new_metas = all_new_vars[n_attrs + n_class_vars:] new_domain = Orange.data.Domain(attrs, class_vars, new_metas) new_data = self.data.from_table(new_domain, self.data) self.send("Data", new_data) def sizeHint(self): sh = super().sizeHint() return sh.expandedTo(QSize(660, 550)) def send_report(self): if self.data is not None: self.report_raw("", EditDomainReport( old_domain=chain(self.data.domain.variables, self.data.domain.metas), new_domain=self.domain_model).to_html()) else: self.report_data(None)
class OWEditDomain(widget.OWWidget): name = "Edit Domain" description = "Rename features and their values." icon = "icons/EditDomain.svg" priority = 3125 class Inputs: data = Input("Data", Orange.data.Table) class Outputs: data = Output("Data", Orange.data.Table) settingsHandler = settings.DomainContextHandler() domain_change_hints = settings.ContextSetting({}) selected_index = settings.ContextSetting({}) autocommit = settings.Setting(True) def __init__(self): super().__init__() self.data = None self.input_vars = () self._invalidated = False box = gui.vBox(self.controlArea, "Domain Features") self.domain_model = itemmodels.VariableListModel() self.domain_view = QListView(selectionMode=QListView.SingleSelection, uniformItemSizes=True) self.domain_view.setModel(self.domain_model) self.domain_view.selectionModel().selectionChanged.connect( self._on_selection_changed) box.layout().addWidget(self.domain_view) box = gui.hBox(self.controlArea) gui.button(box, self, "Reset Selected", callback=self.reset_selected) gui.button(box, self, "Reset All", callback=self.reset_all) gui.auto_commit(self.controlArea, self, "autocommit", "Apply") box = gui.vBox(self.mainArea, "Edit") self.editor_stack = QStackedWidget() self.editor_stack.addWidget(DiscreteVariableEditor()) self.editor_stack.addWidget(ContinuousVariableEditor()) self.editor_stack.addWidget(VariableEditor()) box.layout().addWidget(self.editor_stack) self.Error.add_message("duplicate_var_name", "A variable name is duplicated.") @Inputs.data @check_sql_input def set_data(self, data): """Set input dataset.""" self.closeContext() self.clear() self.data = data if self.data is not None: self._initialize() self.openContext(self.data) self._restore() self.unconditional_commit() def clear(self): """Clear the widget state.""" self.data = None self.domain_model[:] = [] self.input_vars = [] self.domain_change_hints = {} self.selected_index = -1 def reset_selected(self): """Reset the currently selected variable to its original state.""" ind = self.selected_var_index() if ind >= 0: var = self.input_vars[ind] desc = variable_description(var, skip_attributes=True) if desc in self.domain_change_hints: del self.domain_change_hints[desc] self.domain_model[ind] = var self.editor_stack.currentWidget().set_data(var) self._invalidate() def reset_all(self): """Reset all variables to their original state.""" self.domain_change_hints = {} if self.data is not None: # To invalidate stored hints self.domain_model[:] = self.input_vars itemmodels.select_row(self.domain_view, self.selected_index) self._invalidate() def selected_var_index(self): """Return the selected row in 'Domain Features' view.""" rows = self.domain_view.selectedIndexes() assert len(rows) <= 1 return rows[0].row() if rows else -1 def _initialize(self): domain = self.data.domain self.input_vars = domain.variables + domain.metas self.domain_model[:] = list(self.input_vars) def _restore(self): # Restore the variable states from saved settings. def transform(var): vdesc = variable_description(var, skip_attributes=True) if vdesc in self.domain_change_hints: return variable_from_description( self.domain_change_hints[vdesc], compute_value=Orange.preprocess.transformation.Identity( var), ) else: return var self.domain_model[:] = map(transform, self.input_vars) # Restore the variable selection if possible index = self.selected_index if index >= len(self.input_vars): index = 0 if len(self.input_vars) else -1 if index >= 0: itemmodels.select_row(self.domain_view, index) def _on_selection_changed(self): self.selected_index = self.selected_var_index() self.open_editor(self.selected_index) def open_editor(self, index): self.clear_editor() if index < 0: return var = self.domain_model[index] editor_index = 2 if var.is_discrete: editor_index = 0 elif var.is_continuous: editor_index = 1 editor = self.editor_stack.widget(editor_index) self.editor_stack.setCurrentWidget(editor) editor.set_data(var) editor.variable_changed.connect(self._on_variable_changed) def clear_editor(self): current = self.editor_stack.currentWidget() try: current.variable_changed.disconnect(self._on_variable_changed) except Exception: pass current.set_data(None) def _on_variable_changed(self): """User edited the current variable in editor.""" assert 0 <= self.selected_index <= len(self.domain_model) editor = self.editor_stack.currentWidget() # Replace the variable in the 'Domain Features' view/model old_var = self.input_vars[self.selected_index] new_var = editor.get_data().copy( compute_value=Orange.preprocess.transformation.Identity(old_var)) self.domain_model[self.selected_index] = new_var # Store the transformation hint. old_var_desc = variable_description(old_var, skip_attributes=True) self.domain_change_hints[old_var_desc] = variable_description(new_var) self._invalidate() def _invalidate(self): self.commit() def commit(self): """Send the changed data to output.""" new_data = None var_names = [vn.name for vn in self.domain_model] self.Error.duplicate_var_name.clear() if self.data is not None: if len(var_names) == len(set(var_names)): input_domain = self.data.domain n_attrs = len(input_domain.attributes) n_class_vars = len(input_domain.class_vars) all_new_vars = list(self.domain_model) attrs = all_new_vars[:n_attrs] class_vars = all_new_vars[n_attrs:n_attrs + n_class_vars] new_metas = all_new_vars[n_attrs + n_class_vars:] new_domain = Orange.data.Domain(attrs, class_vars, new_metas) new_data = self.data.transform(new_domain) else: self.Error.duplicate_var_name() self.Outputs.data.send(new_data) def sizeHint(self): sh = super().sizeHint() return sh.expandedTo(QSize(660, 550)) def send_report(self): if self.data is not None: self.report_raw( "", EditDomainReport( old_domain=chain(self.data.domain.variables, self.data.domain.metas), new_domain=self.domain_model, ).to_html(), ) else: self.report_data(None)
class LabelSelectionWidget(QWidget): """ A widget for selection of label values. The widget displays the contents of the model with two widgets: * The top level model items are displayed in a combo box. * The children of the current selected top level item are displayed in a subordinate list view. .. note:: This is not a QAbstractItemView subclass. """ # Current group/root index has changed. groupChanged = Signal(int) # Selection for the current group/root has changed. groupSelectionChanged = Signal(int) def __init__(self): super().__init__() self.__model = None self.__selectionMode = QListView.ExtendedSelection self.__currentIndex = -1 self.__selections = {} self.__parent = None self.targets = [] layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) def group_box(title): box = QGroupBox(title) box.setFlat(True) lay = QVBoxLayout() lay.setContentsMargins(0, 0, 0, 0) box.setLayout(lay) return box self.labels_combo = QComboBox() self.values_view = QListView(selectionMode=self.__selectionMode) self.labels_combo.currentIndexChanged.connect( self.__onCurrentIndexChanged) l_box = group_box(self.tr("Label")) v_box = group_box(self.tr("Values")) l_box.layout().addWidget(self.labels_combo) v_box.layout().addWidget(self.values_view) layout.addWidget(l_box) layout.addWidget(v_box) self.setLayout(layout) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) def set_selection(self): model = self.model() # FIX: This assumes fixed target key/values order. indices = [ model.index(i, 0, model.index(keyind, 0)) for keyind, selected in enumerate(self.__parent.stored_selections) for i in selected ] selection = itemselection(indices) self.setCurrentGroupIndex(self.__parent.current_group_index) self.setSelection(selection) def selected_split(self): group_index = self.currentGroupIndex() if not (0 <= group_index < len(self.targets)): return None, [] group = self.targets[group_index] selection = [ ind.row() for ind in self.currentGroupSelection().indexes() ] return group, selection def set_data(self, parent, data): """ Initialize widget state after receiving new data. """ self.__parent = parent # self.__currentIndex = parent.current_group_index if data is not None: column_groups, row_groups = group_candidates(data) self.targets = column_groups + row_groups model = QStandardItemModel() for item in [standarditem_from(desc) for desc in self.targets]: model.appendRow(item) self.setModel(model) else: self.targets = [] self.setModel(None) def clear(self): """ Clear the widget/model (same as ``setModel(None)``). """ if self.__model is not None: self.values_view.selectionModel().clearSelection() self.values_view.selectionModel().selectionChanged.disconnect( self.__onSelectionChanged) self.values_view.setModel(None) self.labels_combo.setModel(QStandardItemModel(self.labels_combo)) self.__currentIndex = -1 self.__selections = {} self.__model = None def setModel(self, model): """ Set the source model for display. The model should be a tree model with depth 2. Parameters ---------- model : QtCore.QAbstractItemModel """ if model is self.__model: return self.clear() if model is None: return self.__model = model self.values_view.setModel(model) self.values_view.setRootIndex(model.index(0, 0)) self.values_view.selectionModel().selectionChanged.connect( self.__onSelectionChanged) # will emit the currentIndexChanged (if the model is not empty) self.labels_combo.setModel(model) def model(self): """ Return the current model. Returns ------- model : QtCore.QAbstractItemModel """ return self.__model def setCurrentGroupIndex(self, index): """ Set the current selected group/root index row. Parameters ---------- index : int Group index. """ self.labels_combo.setCurrentIndex(index) def currentGroupIndex(self): """ Return the current selected group/root index row. Returns ------- row : index Current group row index (-1 if there is no current index) """ return self.labels_combo.currentIndex() def setSelection(self, selection): """ Set the model item selection. Parameters ---------- selection : QtCore.QItemSelection Item selection. """ if self.values_view.selectionModel() is not None: indices = selection.indexes() pind = defaultdict(list) for index in indices: parent = index.parent() if parent.isValid(): if parent == self.__model.index(parent.row(), parent.column()): pind[parent.row()].append(QPersistentModelIndex(index)) else: warnings.warn("Die Die Die") else: # top level index pass self.__selections = pind self.__restoreSelection() def selection(self): """ Return the item selection. Returns ------- selection : QtCore.QItemSelection """ selection = QItemSelection() if self.__model is None: return selection for pind in chain(*self.__selections.values()): ind = self.__model.index(pind.row(), pind.column(), pind.parent()) if ind.isValid(): selection.select(ind, ind) return selection def currentGroupSelection(self): """ Return the item selection for the current group only. """ if self.values_view.selectionModel() is not None: return self.values_view.selectionModel().selection() else: return QItemSelection() def __onCurrentIndexChanged(self, index): self.__storeSelection(self.__currentIndex, self.values_view.selectedIndexes()) self.__currentIndex = index if self.__model is not None: root = self.__model.index(index, 0) self.values_view.setRootIndex(root) self.__restoreSelection() self.groupChanged.emit(index) def __onSelectionChanged(self, old, new): self.__storeSelection(self.__currentIndex, self.values_view.selectedIndexes()) self.groupSelectionChanged.emit(self.__currentIndex) def __storeSelection(self, groupind, indices): # Store current values selection for the current group groupind = self.__currentIndex indices = [ QPersistentModelIndex(ind) for ind in self.values_view.selectedIndexes() ] self.__selections[groupind] = indices def __restoreSelection(self): # Restore previous selection for root (if available) assert self.__model is not None groupind = self.__currentIndex root = self.__model.index(groupind, 0) sel = self.__selections.get(groupind, []) indices = [ self.__model.index(pind.row(), pind.column(), root) for pind in sel if pind.isValid() and pind.parent() == root ] selection = QItemSelection() for ind in indices: selection.select(ind, ind) self.values_view.selectionModel().select( selection, QItemSelectionModel.ClearAndSelect) def sizeHint(self): """Reimplemented from QWidget.sizeHint""" return QSize(100, 200)
class SelectionSetsWidget(QFrame): """ Widget for managing multiple stored item selections """ selectionModified = Signal(bool) def __init__(self, parent): QFrame.__init__(self, parent) self.setContentsMargins(0, 0, 0, 0) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(1) self._setNameLineEdit = QLineEdit(self) layout.addWidget(self._setNameLineEdit) self._setListView = QListView(self) self._listModel = QStandardItemModel(self) self._proxyModel = QSortFilterProxyModel(self) self._proxyModel.setSourceModel(self._listModel) self._setListView.setModel(self._proxyModel) self._setListView.setItemDelegate(ListItemDelegate(self)) self._setNameLineEdit.textChanged.connect( self._proxyModel.setFilterFixedString) self._completer = QCompleter(self._listModel, self) self._setNameLineEdit.setCompleter(self._completer) self._listModel.itemChanged.connect(self._onSetNameChange) layout.addWidget(self._setListView) buttonLayout = QHBoxLayout() self._addAction = QAction( "+", self, toolTip="Add a new sort key") self._updateAction = QAction( "Update", self, toolTip="Update/save current selection") self._removeAction = QAction( "\u2212", self, toolTip="Remove selected sort key.") self._addToolButton = QToolButton(self) self._updateToolButton = QToolButton(self) self._removeToolButton = QToolButton(self) self._updateToolButton.setSizePolicy( QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) self._addToolButton.setDefaultAction(self._addAction) self._updateToolButton.setDefaultAction(self._updateAction) self._removeToolButton.setDefaultAction(self._removeAction) buttonLayout.addWidget(self._addToolButton) buttonLayout.addWidget(self._updateToolButton) buttonLayout.addWidget(self._removeToolButton) layout.addLayout(buttonLayout) self.setLayout(layout) self._addAction.triggered.connect(self.addCurrentSelection) self._updateAction.triggered.connect(self.updateSelectedSelection) self._removeAction.triggered.connect(self.removeSelectedSelection) self._setListView.selectionModel().selectionChanged.connect( self._onListViewSelectionChanged) self.selectionModel = None self._selections = [] def sizeHint(self): size = QFrame.sizeHint(self) return QSize(size.width(), 150) def _onSelectionChanged(self, selected, deselected): self.setSelectionModified(True) def _onListViewSelectionChanged(self, selected, deselected): try: index = self._setListView.selectedIndexes()[0] except IndexError: return self.commitSelection(self._proxyModel.mapToSource(index).row()) def _onSetNameChange(self, item): self.selections[item.row()].name = str(item.text()) def _setButtonStates(self, val): self._updateToolButton.setEnabled(val) def setSelectionModel(self, selectionModel): if self.selectionModel: self.selectionModel.selectionChanged.disconnect( self._onSelectionChanged) self.selectionModel = selectionModel self.selectionModel.selectionChanged.connect(self._onSelectionChanged) def addCurrentSelection(self): item = self.addSelection( SelectionByKey(self.selectionModel.selection(), name="New selection", key=(1, 2, 3, 10))) index = self._proxyModel.mapFromSource(item.index()) self._setListView.setCurrentIndex(index) self._setListView.edit(index) self.setSelectionModified(False) def removeSelectedSelection(self): i = self._proxyModel.mapToSource(self._setListView.currentIndex()).row() self._listModel.takeRow(i) del self.selections[i] def updateCurentSelection(self): i = self._proxyModel.mapToSource(self._setListView.selectedIndex()).row() self.selections[i].setSelection(self.selectionModel.selection()) self.setSelectionModified(False) def addSelection(self, selection, name=""): self._selections.append(selection) item = QStandardItem(selection.name) item.setFlags(item.flags() ^ Qt.ItemIsDropEnabled) self._listModel.appendRow(item) self.setSelectionModified(False) return item def updateSelectedSelection(self): i = self._proxyModel.mapToSource(self._setListView.currentIndex()).row() self.selections[i].setSelection(self.selectionModel.selection()) self.setSelectionModified(False) def setSelectionModified(self, val): self._selectionModified = val self._setButtonStates(val) self.selectionModified.emit(bool(val)) def commitSelection(self, index): selection = self.selections[index] selection.select(self.selectionModel) def setSelections(self, selections): self._listModel.clear() for selection in selections: self.addSelection(selection) def selections(self): return self._selections selections = property(selections, setSelections)
class SelectionSetsWidget(QFrame): """ Widget for managing multiple stored item selections """ selectionModified = Signal(bool) def __init__(self, parent): QFrame.__init__(self, parent) self.setContentsMargins(0, 0, 0, 0) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(1) self._setNameLineEdit = QLineEdit(self) layout.addWidget(self._setNameLineEdit) self._setListView = QListView(self) self._listModel = QStandardItemModel(self) self._proxyModel = QSortFilterProxyModel(self) self._proxyModel.setSourceModel(self._listModel) self._setListView.setModel(self._proxyModel) self._setListView.setItemDelegate(ListItemDelegate(self)) self._setNameLineEdit.textChanged.connect( self._proxyModel.setFilterFixedString) self._completer = QCompleter(self._listModel, self) self._setNameLineEdit.setCompleter(self._completer) self._listModel.itemChanged.connect(self._onSetNameChange) layout.addWidget(self._setListView) buttonLayout = QHBoxLayout() self._addAction = QAction("+", self, toolTip="Add a new sort key") self._updateAction = QAction("Update", self, toolTip="Update/save current selection") self._removeAction = QAction("\u2212", self, toolTip="Remove selected sort key.") self._addToolButton = QToolButton(self) self._updateToolButton = QToolButton(self) self._removeToolButton = QToolButton(self) self._updateToolButton.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) self._addToolButton.setDefaultAction(self._addAction) self._updateToolButton.setDefaultAction(self._updateAction) self._removeToolButton.setDefaultAction(self._removeAction) buttonLayout.addWidget(self._addToolButton) buttonLayout.addWidget(self._updateToolButton) buttonLayout.addWidget(self._removeToolButton) layout.addLayout(buttonLayout) self.setLayout(layout) self._addAction.triggered.connect(self.addCurrentSelection) self._updateAction.triggered.connect(self.updateSelectedSelection) self._removeAction.triggered.connect(self.removeSelectedSelection) self._setListView.selectionModel().selectionChanged.connect( self._onListViewSelectionChanged) self.selectionModel = None self._selections = [] def sizeHint(self): size = QFrame.sizeHint(self) return QSize(size.width(), 150) def _onSelectionChanged(self, selected, deselected): self.setSelectionModified(True) def _onListViewSelectionChanged(self, selected, deselected): try: index = self._setListView.selectedIndexes()[0] except IndexError: return self.commitSelection(self._proxyModel.mapToSource(index).row()) def _onSetNameChange(self, item): self.selections[item.row()].name = str(item.text()) def _setButtonStates(self, val): self._updateToolButton.setEnabled(val) def setSelectionModel(self, selectionModel): if self.selectionModel: self.selectionModel.selectionChanged.disconnect( self._onSelectionChanged) self.selectionModel = selectionModel self.selectionModel.selectionChanged.connect(self._onSelectionChanged) def addCurrentSelection(self): item = self.addSelection( SelectionByKey(self.selectionModel.selection(), name="New selection", key=(1, 2, 3, 10))) index = self._proxyModel.mapFromSource(item.index()) self._setListView.setCurrentIndex(index) self._setListView.edit(index) self.setSelectionModified(False) def removeSelectedSelection(self): i = self._proxyModel.mapToSource( self._setListView.currentIndex()).row() self._listModel.takeRow(i) del self.selections[i] def updateCurentSelection(self): i = self._proxyModel.mapToSource( self._setListView.selectedIndex()).row() self.selections[i].setSelection(self.selectionModel.selection()) self.setSelectionModified(False) def addSelection(self, selection, name=""): self._selections.append(selection) item = QStandardItem(selection.name) item.setFlags(item.flags() ^ Qt.ItemIsDropEnabled) self._listModel.appendRow(item) self.setSelectionModified(False) return item def updateSelectedSelection(self): i = self._proxyModel.mapToSource( self._setListView.currentIndex()).row() self.selections[i].setSelection(self.selectionModel.selection()) self.setSelectionModified(False) def setSelectionModified(self, val): self._selectionModified = val self._setButtonStates(val) self.selectionModified.emit(bool(val)) def commitSelection(self, index): selection = self.selections[index] selection.select(self.selectionModel) def setSelections(self, selections): self._listModel.clear() for selection in selections: self.addSelection(selection) def selections(self): return self._selections selections = property(selections, setSelections)