Skip to content

Commit f6339ea

Browse files
authored
Merge 22334cc into 29b6a9b
2 parents 29b6a9b + 22334cc commit f6339ea

5 files changed

Lines changed: 76 additions & 2 deletions

File tree

source/gui/addonStoreGui/controls/storeDialog.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,18 @@ def _createFilterControls(self, filterCtrlHelper: guiHelper.BoxSizerHelper) -> N
155155
filterCtrlsLine1.sizer.AddSpacer(FILTER_MARGIN_PADDING)
156156
filterCtrlHelper.addItem(filterCtrlsLine1.sizer, flag=wx.EXPAND, proportion=1)
157157

158+
self.columnFilterCtrl = cast(
159+
wx.Choice,
160+
filterCtrlsLine0.addLabeledControl(
161+
# Translators: The label of a selection field to sort the list of add-ons in the add-on store dialog.
162+
labelText=pgettext("addonStore", "Sort by colu&mn:"),
163+
wxCtrlClass=wx.Choice,
164+
choices=self._storeVM.listVM._columnSortChoices,
165+
),
166+
)
167+
self.columnFilterCtrl.Bind(wx.EVT_CHOICE, self.onColumnFilterChange, self.columnFilterCtrl)
168+
self.bindHelpEvent("AddonStoreSortByColumn", self.columnFilterCtrl)
169+
158170
self.channelFilterCtrl = cast(
159171
wx.Choice,
160172
filterCtrlsLine0.addLabeledControl(
@@ -323,6 +335,9 @@ def _setListLabels(self):
323335
self.SetTitle(self._titleText)
324336

325337
def _toggleFilterControls(self):
338+
self.columnFilterCtrl.Clear()
339+
for c in self._storeVM.listVM._columnSortChoices:
340+
self.columnFilterCtrl.Append(c)
326341
self.channelFilterCtrl.Clear()
327342
for c in _channelFilters:
328343
if c != Channel.EXTERNAL:
@@ -358,6 +373,8 @@ def onListTabPageChange(self, evt: wx.EVT_CHOICE):
358373
self._storeVM._filteredStatusKey = self._statusFilterKey
359374
self.addonListView._refreshColumns()
360375
self._toggleFilterControls()
376+
self.columnFilterCtrl.SetSelection(0)
377+
self._storeVM.listVM.setSortField(self._storeVM.listVM.presentedFields[0])
361378

362379
channelFilterIndex = list(_channelFilters.keys()).index(self._storeVM._filterChannelKey)
363380
self.channelFilterCtrl.SetSelection(channelFilterIndex)
@@ -370,6 +387,15 @@ def onListTabPageChange(self, evt: wx.EVT_CHOICE):
370387
if not self.addonListTabs.HasFocus():
371388
self.addonListTabs.SetFocus()
372389

390+
def onColumnFilterChange(self, evt: wx.EVT_CHOICE):
391+
# Each col index will correspond to 2 choices in the combo box (ascending and descending)
392+
colIndex = evt.GetSelection() // 2
393+
# Descending sort should be applied for odd choices of the combo box
394+
reverse = evt.GetSelection() % 2
395+
self._storeVM.listVM.setSortField(self._storeVM.listVM.presentedFields[colIndex], reverse)
396+
log.debug(f"sortered by: {colIndex}; reversed: {reverse}")
397+
self._storeVM.refresh()
398+
373399
def onChannelFilterChange(self, evt: wx.EVT_CHOICE):
374400
self._storeVM._filterChannelKey = self._channelFilterKey
375401
self._storeVM.listVM.setSelection(None)

source/gui/addonStoreGui/viewModels/addonList.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ def __init__(
220220
self.lastSelectedAddonId = self.selectedAddonId
221221
self._sortByModelField: AddonListField = AddonListField.displayName
222222
self._filterString: Optional[str] = None
223+
self._reverseSort: bool = False
223224

224225
self._setSelectionPending = False
225226
self._addonsFilteredOrdered: List[str] = self._getFilteredSortedIds()
@@ -340,15 +341,42 @@ def _validate(
340341
if selectionId is not None:
341342
assert selectionId in self._addons.keys()
342343

343-
def setSortField(self, modelField: AddonListField):
344+
def setSortField(self, modelField: AddonListField, reverse: bool = False):
344345
oldOrder = self._addonsFilteredOrdered
345346
self._validate(sortField=modelField)
346347
self._sortByModelField = modelField
348+
self._reverseSort = reverse
347349
self._updateAddonListing()
348350
if oldOrder != self._addonsFilteredOrdered:
349351
# ensure calling on the main thread.
350352
core.callLater(delay=0, callable=self.updated.notify)
351353

354+
@property
355+
def _columnSortChoices(self) -> list[str]:
356+
columnChoices = []
357+
for c in self.presentedFields:
358+
# Translators: An option of a combo box to sort columns in the add-on store, in ascending order.
359+
# {column} will be replaced with the column display string.
360+
columnChoices.append(
361+
pgettext(
362+
"addonStore",
363+
"{column} (ascending)",
364+
).format(
365+
column=c.displayString,
366+
),
367+
)
368+
# Translators: An option of a combo box to sort columns in the add-on store, in descending order.
369+
# {column} will be replaced with the column display string.
370+
columnChoices.append(
371+
pgettext(
372+
"addonStore",
373+
"{column} (descending)",
374+
).format(
375+
column=c.displayString,
376+
),
377+
)
378+
return columnChoices
379+
352380
def _getFilteredSortedIds(self) -> List[str]:
353381
def _getSortFieldData(listItemVM: AddonListItemVM) -> "SupportsLessThan":
354382
return strxfrm(self._getAddonFieldText(listItemVM, self._sortByModelField))
@@ -371,7 +399,9 @@ def _containsTerm(detailsVM: AddonListItemVM, term: str) -> bool:
371399
for vm in self._addons.values()
372400
if self._filterString is None or _containsTerm(vm, self._filterString)
373401
)
374-
filteredSorted = list([vm.Id for vm in sorted(filtered, key=_getSortFieldData)])
402+
filteredSorted = list(
403+
[vm.Id for vm in sorted(filtered, key=_getSortFieldData, reverse=self._reverseSort)],
404+
)
375405
return filteredSorted
376406

377407
def _tryPersistSelection(

tests/manual/addonStore.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,16 @@ Add-ons can be filtered by display name, publisher and description.
3030
1. Enable the "Include incompatible add-ons" filter
3131
1. Ensure add-ons with status "incompatible" are included in the list with the available add-ons.
3232

33+
### Sorting the add-ons list by column
34+
1. Open the Add-on Store
35+
1. Sort by column:
36+
1. Using the combo-box:
37+
1. Jump to the sort by column field (`alt+m`)
38+
1. Select different columns (ascending or descending order)
39+
1. Alternatively, perform a left mouse click on different columns
40+
1. Ensure that the add-ons list is sorted accordingly
41+
1. Change to different tabs, and repeat the previous steps.
42+
3343
### Failure to fetch add-ons available for download
3444
1. Disable your internet connection
3545
1. Go to your [NVDA user configuration folder](#editing-user-configuration)

user_docs/en/changes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ In order to use this feature, the application volume adjuster needs to be enable
1515
* Added an action in the Add-on Store to cancel the install of add-ons. (#15578, @hwf1324)
1616
* Added an action in the Add-on Store to retry the installation if the download/installation of an add-on fails. (#17090, @hwf1324)
1717
* It is now possible to specify a mirror URL to use for the Add-on Store. (#14974)
18+
* The add-ons lists in the Add-on Store can be sorted by columns. (#15277, @nvdaes)
1819
* When decreasing or increasing the font size in LibreOffice Writer using the corresponding keyboard shortcuts, NVDA announces the new font size. (#6915, @michaelweghorn)
1920
* Automatic language switching is now supported when using Microsoft Speech API version 5 (SAPI5) and Microsoft Speech Platform voices. (#17146, @gexgd0419)
2021

user_docs/en/userGuide.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3637,6 +3637,13 @@ You can reach it by pressing `shift+tab` from the list of add-ons.
36373637
Type a keyword or two for the kind of add-on you're looking for, then `tab` to the list of add-ons.
36383638
Add-ons will be listed if the search text can be found in the add-on ID, display name, publisher, author or description.
36393639

3640+
#### Sorting the add-ons list by column {#AddonStoreSortByColumn}
3641+
3642+
By default, the add-ons list is sorted by the add-ons' display name.
3643+
The "Sort by column" combo box can be used to sort the list by the available columns for each tab.
3644+
For example, you may wish to sort add-ons by publisher, available version, etc.
3645+
Add-ons can be sortered in ascending or descending order.
3646+
36403647
### Add-on actions {#AddonStoreActions}
36413648

36423649
Add-ons have associated actions, such as install, help, disable, and remove.

0 commit comments

Comments
 (0)