diff --git a/spyder/plugins/variableexplorer/widgets/collectionsdelegate.py b/spyder/plugins/variableexplorer/widgets/collectionsdelegate.py index 218eaffc197..4b875371514 100644 --- a/spyder/plugins/variableexplorer/widgets/collectionsdelegate.py +++ b/spyder/plugins/variableexplorer/widgets/collectionsdelegate.py @@ -19,6 +19,8 @@ from qtpy.QtCore import ( QDateTime, QEvent, + QItemSelection, + QItemSelectionModel, QModelIndex, QRect, QSize, @@ -525,7 +527,11 @@ def paint(self, painter, option, index): x, y, SELECT_ROW_BUTTON_SIZE, SELECT_ROW_BUTTON_SIZE ) button.text = "" - button.icon = ima.icon("select_row") + button.icon = ( + ima.icon("select_row") + if index.row() not in self.parent().selected_rows() + else ima.icon("deselect_row") + ) button.iconSize = QSize(20, 20) button.state = QStyle.State_Enabled QApplication.style().drawControl( @@ -552,9 +558,19 @@ def editorEvent(self, event, model, option, index): x = rect.left() + rect.width() - SELECT_ROW_BUTTON_SIZE y = rect.top() - # Select row when clicking on the button + # Select/deselect row when clicking on the button if click_x > x and (y < click_y < (y + SELECT_ROW_BUTTON_SIZE)): - self.parent().selectRow(index.row()) + row = index.row() + if row in self.parent().selected_rows(): + # Deselect row if selected + index_left = index.sibling(row, 0) + index_right = index.sibling(row, 3) + selection = QItemSelection(index_left, index_right) + self.parent().selectionModel().select( + selection, QItemSelectionModel.Deselect + ) + else: + self.parent().selectRow(row) else: super().editorEvent(event, model, option, index) else: diff --git a/spyder/utils/icon_manager.py b/spyder/utils/icon_manager.py index 16125a476b7..1ce13d1216c 100644 --- a/spyder/utils/icon_manager.py +++ b/spyder/utils/icon_manager.py @@ -215,6 +215,7 @@ def __init__(self): 'move': [('mdi.file-move',), {'color': self.MAIN_FG_COLOR}], 'edit_add': [('mdi.plus-box',), {'color': self.MAIN_FG_COLOR}], 'select_row': [('mdi.plus-box-outline',), {'color': self.MAIN_FG_COLOR}], + 'deselect_row': [('mdi.minus-box-outline',), {'color': self.MAIN_FG_COLOR}], 'duplicate_row': [('ph.rows',), {'color': self.MAIN_FG_COLOR}], 'duplicate_column': [('ph.columns',), {'color': self.MAIN_FG_COLOR}], 'collapse_column': [('mdi.arrow-collapse-horizontal',), {'color': self.MAIN_FG_COLOR}], diff --git a/spyder/widgets/collectionseditor.py b/spyder/widgets/collectionseditor.py index c1510bc0b6a..41e6ee5522a 100644 --- a/spyder/widgets/collectionseditor.py +++ b/spyder/widgets/collectionseditor.py @@ -483,10 +483,13 @@ def data(self, index, role=Qt.DisplayRole): display = value if role == Qt.ToolTipRole: if self.parent().over_select_row_button: - tooltip = _( - "Click to select this row. Maintain pressed Ctrl (Cmd on " - "macOS) for multiple rows" - ) + if index.row() in self.parent().selected_rows(): + tooltip = _("Click to deselect this row") + else: + tooltip = _( + "Click to select this row. Maintain pressed Ctrl (Cmd " + "on macOS) for multiple rows" + ) return '\n'.join(textwrap.wrap(tooltip, 50)) return display if role == Qt.UserRole: @@ -1500,6 +1503,12 @@ def paste(self): QMessageBox.warning(self, _( "Empty clipboard"), _("Nothing to be imported from clipboard.")) + def selected_rows(self): + """Get the rows currently selected.""" + return [ + index.row() for index in self.selectionModel().selectedRows() + ] + class CollectionsEditorTableView(BaseTableView): """CollectionsEditor table view"""