|
12 | 12 | QPalette, |
13 | 13 | QColor |
14 | 14 | ) |
15 | | -from PySide6.QtCore import Qt |
| 15 | +from PySide6.QtCore import Qt, QItemSelection, QItemSelectionModel |
16 | 16 |
|
17 | 17 | from .data_table import DataTable |
18 | 18 | from .history import HistoryTableWidget |
|
36 | 36 | TextWidget, |
37 | 37 | ) |
38 | 38 |
|
| 39 | + |
| 40 | +def invert_object_rows(row_names : list, selected : set): |
| 41 | + """Return the row indices to select when inverting an object selection. |
| 42 | +
|
| 43 | + Every row that is not currently selected becomes selected. Object rows are |
| 44 | + freely selectable in the list (no lock restriction), so nothing is excluded |
| 45 | + here -- this matches the object list's existing selection behavior. |
| 46 | +
|
| 47 | + Params: |
| 48 | + row_names (list): object name at each row, in row order |
| 49 | + selected (set): names of the currently selected objects |
| 50 | + Returns: |
| 51 | + (list): the row indices that should end up selected |
| 52 | + """ |
| 53 | + return [r for r, name in enumerate(row_names) if name not in selected] |
| 54 | + |
| 55 | + |
39 | 56 | class ObjectTableWidget(DataTable): |
40 | 57 |
|
41 | 58 | def __init__(self, series : Series, mainwindow : QWidget, manager, hidden=False): |
@@ -130,6 +147,17 @@ def getCall(col_name, opt_name): |
130 | 147 | ("export_act", "Export...", "", self.export), |
131 | 148 | ] |
132 | 149 | }, |
| 150 | + { |
| 151 | + "attr_name": "selectionmenu", |
| 152 | + "text": "Selection", |
| 153 | + "opts": |
| 154 | + [ |
| 155 | + ("invertobjselection_act", "Invert selection", "", self.invertSelection), |
| 156 | + None, |
| 157 | + ("hideunselectedobj_act1", "Hide unselected objects", "", self.mainwindow.field.hideUnselectedObjects), |
| 158 | + ("showallobj_act1", "Show all objects", "", self.mainwindow.field.unhideAllObjects), |
| 159 | + ] |
| 160 | + }, |
133 | 161 | { |
134 | 162 | "attr_name": "filtermenu", |
135 | 163 | "text": "Filter", |
@@ -194,8 +222,13 @@ def getCall(col_name, opt_name): |
194 | 222 | # fill in the menu bar object |
195 | 223 | populateMenuBar(self, self.menubar, menubar_list) |
196 | 224 |
|
197 | | - # create the right-click menu |
198 | | - context_menu_list = self.mainwindow.field.getObjMenu() |
| 225 | + # create the right-click menu -- prepend the object-list-only |
| 226 | + # "Invert selection" (a table selection op, so it lives here rather |
| 227 | + # than in the shared field object menu) |
| 228 | + context_menu_list = [ |
| 229 | + ("invertobjselection_act1", "Invert selection", "", self.invertSelection), |
| 230 | + None, |
| 231 | + ] + self.mainwindow.field.getObjMenu() |
199 | 232 | self.context_menu = QMenu(self) |
200 | 233 | populateMenu(self, self.context_menu, context_menu_list) |
201 | 234 |
|
@@ -575,6 +608,32 @@ def getSelected(self, single=False): |
575 | 608 | else: |
576 | 609 | return obj_names |
577 | 610 |
|
| 611 | + def invertSelection(self): |
| 612 | + """Invert which objects are selected in the list. |
| 613 | +
|
| 614 | + Every object shown in the list that is not currently selected becomes |
| 615 | + selected, and vice versa. Operates on the rows currently displayed, so |
| 616 | + with no active filter this inverts against every object in the series. |
| 617 | + """ |
| 618 | + row_count = self.table.rowCount() |
| 619 | + if not row_count: |
| 620 | + return |
| 621 | + |
| 622 | + row_names = [self.table.item(r, 0).text() for r in range(row_count)] |
| 623 | + selected = set(self.getSelected()) |
| 624 | + to_select = invert_object_rows(row_names, selected) |
| 625 | + |
| 626 | + model = self.table.model() |
| 627 | + last_col = self.table.columnCount() - 1 |
| 628 | + new_selection = QItemSelection() |
| 629 | + for r in to_select: |
| 630 | + new_selection.select(model.index(r, 0), model.index(r, last_col)) |
| 631 | + |
| 632 | + self.table.selectionModel().select( |
| 633 | + new_selection, |
| 634 | + QItemSelectionModel.ClearAndSelect |
| 635 | + ) |
| 636 | + |
578 | 637 | def itemChanged(self, item : QTableWidgetItem): |
579 | 638 | """User checked a checkbox.""" |
580 | 639 | # check for curation |
|
0 commit comments