Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions installer/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,9 +469,8 @@ def generate_build_metadata(args: argparse.Namespace) -> None:

def _in_virtual_environment() -> bool:
"""Return True when running inside an activated Python virtual environment."""
return (
sys.prefix != getattr(sys, "base_prefix", sys.prefix)
or bool(os.environ.get("VIRTUAL_ENV"))
return sys.prefix != getattr(sys, "base_prefix", sys.prefix) or bool(
os.environ.get("VIRTUAL_ENV")
)


Expand Down
17 changes: 14 additions & 3 deletions src/portkeydrop/dialogs/site_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,26 @@ def _on_char_hook(self, event: wx.KeyEvent) -> None:
def _on_remove(self, event: wx.CommandEvent) -> None:
if self._selected_site:
idx = self.site_list.GetSelection()
if idx == wx.NOT_FOUND:
# Fall back to the selected site's index when list selection is stale.
selected_id = self._selected_site.id
idx = wx.NOT_FOUND
for i in range(self.site_list.GetCount()):
if self.site_list.GetClientData(i) == selected_id:
idx = i
break
self._site_manager.remove(self._selected_site.id)
self._selected_site = None
self._refresh_site_list()
# Set focus to the next item, or the last item, or the list itself
# Select next item (or previous if removed last), then return focus to list.
count = self.site_list.GetCount()
if count > 0:
new_idx = min(idx, count - 1)
new_idx = min(idx, count - 1) if idx != wx.NOT_FOUND else 0
self.site_list.SetSelection(new_idx)
self.site_list.SetFocus()
self._selected_site = self._site_manager.sites[new_idx]
focus_list = getattr(wx, "CallAfter", None)
if callable(focus_list):
focus_list(self.site_list.SetFocus)
else:
self.site_list.SetFocus()

Expand Down
27 changes: 27 additions & 0 deletions tests/test_site_manager_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ def _make_fake_wx():
wx.EVT_LISTBOX = object()
wx.EVT_CHAR_HOOK = object()
wx.MessageBox = MagicMock(return_value=wx.OK)
wx.CallAfter = lambda fn, *a, **kw: fn(*a, **kw)
return wx


Expand Down Expand Up @@ -451,3 +452,29 @@ def test_remove_only_item_focuses_list(self, dialog_module):
# No items left, focus should go to the list itself
assert dlg.site_list.GetCount() == 0
assert dlg.site_list._focused is True

def test_remove_with_stale_selection_uses_selected_site_index(self, dialog_module):
mod, fake_wx = dialog_module
dlg, sites = self._make_dialog_with_sites(mod, fake_wx, ["A", "B", "C"])

# Simulate stale list selection while a site is still logically selected.
dlg.site_list.SetSelection(fake_wx.NOT_FOUND)
dlg._selected_site = sites[1]

mod.SiteManagerDialog._on_remove(dlg, MagicMock())

# Should still select/focus index 1 (now "C").
assert dlg.site_list._selection == 1
assert dlg.site_list._focused is True

def test_remove_updates_selected_site_to_remaining_selection(self, dialog_module):
mod, fake_wx = dialog_module
dlg, sites = self._make_dialog_with_sites(mod, fake_wx, ["A", "B", "C"])

dlg.site_list.SetSelection(1)
dlg._selected_site = sites[1]

mod.SiteManagerDialog._on_remove(dlg, MagicMock())

# Logical selection should track the newly selected row ("C").
assert dlg._selected_site is dlg._site_manager.sites[1]
Loading