Show the status of add-ons in the system config when copying user config to system config (#19808)
Closes #19550
### Summary of the issue:
Since #19446, users can select which add-ons should be copied to the
system-wide configuration when replacing it with their current user
configuration. However, they cannot see whether an add-on is already
present in the system configuration, and if so which version is present.
### Description of user facing changes:
* A new "System-wide version" column has been added to the copy
add-ons dialog, which shows the version of the add-on present in the
system config, if any.
* The "Version" column in the same dialog has been renamed to "User
version" to disambiguate it from the new "System-wide version" column.
* The "Author" column in this dialog has been removed to cut down on
verbosity. Author information is still available via the "About
add-on..." button.
* The list of add-ons now contains entries for add-ons which are
only present in the system-wide configuration. In the case of these
add-ons, the list item does not have an associated checkbox, and the
name is prefixed with "[remove]".
* The text in the dialogs has been updated to reflect that add-ons
only present in the system configuration will be removed when replacing
it with the user config.
* Add-ons in the user configuration are checked by default if they
also exist in the system-wide configuration.
### Description of developer facing changes:
None in public API
### Description of development approach:
* Added a function to get add-on manifests from a directory without
side-effects. This is similar to existing functionality, and this code
should probably be refactored to reduce duplication. However, given how
close we are to a release, this approach is safer.
* Updated `_CopyAddonsDialog` to take two dictionaries - one mapping
add-on names to `Addon` objects from the user config; and one mapping
add-on names to `AddonManifest` objects from the system config (gathered
with the new new `_getAddonManifestsFromPath` function).
* Updated the prereqs for showing the copy add-ons dialog. It now
requires that the user and system add-ons between them contain at least
one add-on.
* Created a tuple of (user `AddonManifest`, system `AddonManifest`)
pairs, and used that to populate the add-ons list. This allows us to
show details of the user and system add-ons.
* Created a subclass of `wx.ListCtrl` which allows removing the checkbox
from specific list items.
* This works by sending a window message to the underlying win32
`ListView` which sets the item's state image to `0` (`0` is no checkbox,
`1` is unchecked and `2` is checked).
* It also replaces the window proc for the containing dialog so that it
can intercept and reject item state changing messages from the list
control where those notifications represent attempting to check or
uncheck an item which has had its checkbox removed. In all other cases,
the original window proc is called.
* Finally, it overrides the `IsItemChecked` implementation, since the
win32 macro that wx uses internally returns evaluates to true if the
state image is set to `0`.
* Used this new control to show the list of add-ons. In the case of
add-ons that are only present in the system config, the checkbox is
removed. Since the list of all add-ons is constructed in such a way that
these add-ons are strictly after add-ons that are present in the user
config, the logic regarding getting copyable add-on IDs elsewhere in the
dialog doesn't need to change.
* Throughout the dialog, where there is no clear way to decide whether
to use the user or system copy of an add-on, the user version is
preferred, and the system copy is used as a fallback.
### Testing strategy:
Tested interacting with the dialog with various combinations of add-ons
in the user and system configurations, and that in all cases the
expected list of add-on IDs was returned. Testing was done by calling
`from gui.addonStoreGui.controls.messageDialogs import
_getAddonsToCopy;_getAddonsToCopy(None)` in the python console when
running from source. `_getAddonsToCopy` was slightly modified to force
it to use `%ProgramFiles%\nvda\systemConfig\addons`.
### Known issues with pull request:
None known