clan-vm-manager: Preserved selection on view change
All checks were successful
checks-impure / test (pull_request) Successful in 1m26s
checks / test (pull_request) Successful in 2m3s

This commit is contained in:
Luis Hebendanz 2023-12-04 14:29:05 +01:00
parent 354291440a
commit 82fb1c36fe
7 changed files with 71 additions and 32 deletions

View File

@ -23,6 +23,7 @@
treefmt.programs.mypy.enable = true;
treefmt.programs.mypy.directories = {
"pkgs/clan-cli".extraPythonPackages = self'.packages.clan-cli.pytestDependencies;
"pkgs/clan-vm-manager".extraPythonPackages = self'.packages.clan-vm-manager.propagatedBuildInputs;
};
treefmt.settings.formatter.nix = {

View File

@ -55,5 +55,5 @@ ignore_missing_imports = true
[tool.ruff]
target-version = "py311"
line-length = 88
select = [ "E", "F", "I", "U", "N", "RUF", "ANN", "A" ]
select = [ "E", "F", "I", "N", "RUF", "ANN", "A" ]
ignore = ["E501", "E402", "ANN101", "ANN401", "A003"]

View File

@ -7,5 +7,7 @@
"path": "../clan-cli/clan_cli"
}
],
"settings": {}
"settings": {
"python.linting.mypyEnabled": true
}
}

View File

@ -16,7 +16,7 @@ from .ui.clan_select_list import ClanEdit, ClanList
class ClanJoinPage(Gtk.Box):
def __init__(self, stack: Gtk.Stack) -> None:
def __init__(self, *, stack: Gtk.Stack) -> None:
super().__init__()
self.page = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL, spacing=6, expand=True
@ -51,12 +51,22 @@ class MainWindow(Gtk.ApplicationWindow):
self.stack = Gtk.Stack()
# self.stack_switcher = Gtk.StackSwitcher()
self.list_hooks = {
"remount_list": self.remount_list_view,
"remount_edit": self.remount_edit_view,
"set_selected": self.set_selected,
}
clan_list = ClanList(**self.list_hooks, selected_vm=None) # type: ignore
# Add named stacks
self.stack.add_titled(clan_list, "list", "List")
self.stack.add_titled(
ClanList(self.show_list, self.show_edit, self.set_selected), "list", "List"
ClanJoinPage(stack=self.remount_list_view), "join", "Join"
)
self.stack.add_titled(
ClanEdit(remount_list=self.remount_list_view, selected_vm=None),
"edit",
"Edit",
)
self.stack.add_titled(ClanJoinPage(self.show_list), "join", "Join")
self.stack.add_titled(ClanEdit(self.show_list, None), "edit", "Edit")
vbox.add(self.stack)
@ -64,28 +74,31 @@ class MainWindow(Gtk.ApplicationWindow):
self.show_all()
def set_selected(self, sel: VMBase | None) -> None:
self.selected = sel
print(f"APP selected + {self.selected}")
self.selected_vm = sel
print(f"APP selected + {self.selected_vm}")
def show_list(self) -> None:
def remount_list_view(self) -> None:
widget = self.stack.get_child_by_name("list")
print("Remounting ClanListView")
if widget:
widget.destroy()
self.stack.add_titled(
ClanList(self.show_list, self.show_edit, self.set_selected), "list", "List"
)
clan_list = ClanList(**self.list_hooks, selected_vm=self.selected_vm) # type: ignore
self.stack.add_titled(clan_list, "list", "List")
self.show_all()
self.stack.set_visible_child_name("list")
def show_edit(self) -> None:
def remount_edit_view(self) -> None:
print("Remounting ClanEdit")
widget = self.stack.get_child_by_name("edit")
if widget:
widget.destroy()
self.stack.add_titled(ClanEdit(self.show_list, self.selected), "edit", "Edit")
self.stack.add_titled(
ClanEdit(remount_list=self.remount_list_view, selected_vm=self.selected_vm),
"edit",
"Edit",
)
self.show_all()
self.stack.set_visible_child_name("edit")

View File

@ -6,7 +6,7 @@ from ..models import VMBase, get_initial_vms
class ClanEditForm(Gtk.ListBox):
def __init__(self, selected: VMBase | None) -> None:
def __init__(self, *, selected: VMBase | None) -> None:
super().__init__()
self.page = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, expand=True)
self.set_border_width(10)
@ -47,11 +47,13 @@ class ClanEditForm(Gtk.ListBox):
class ClanEdit(Gtk.Box):
def __init__(self, show_list: Callable[[], None], selected: VMBase | None) -> None:
def __init__(
self, *, remount_list: Callable[[], None], selected_vm: VMBase | None
) -> None:
super().__init__(orientation=Gtk.Orientation.VERTICAL, expand=True)
self.show_list = show_list
self.selected = selected
self.show_list = remount_list
self.selected = selected_vm
button_hooks = {
"on_save_clicked": self.on_save,
@ -59,7 +61,7 @@ class ClanEdit(Gtk.Box):
self.toolbar = ClanEditToolbar(**button_hooks)
self.add(self.toolbar)
self.add(ClanEditForm(self.selected))
self.add(ClanEditForm(selected=self.selected))
def on_save(self, widget: Gtk.Widget) -> None:
print("Save clicked saving values")
@ -82,14 +84,16 @@ class ClanList(Gtk.Box):
def __init__(
self,
show_list: Callable[[], None],
show_edit: Callable[[], None],
*,
remount_list: Callable[[], None],
remount_edit: Callable[[], None],
set_selected: Callable[[VMBase | None], None],
selected_vm: VMBase | None,
) -> None:
super().__init__(orientation=Gtk.Orientation.VERTICAL, expand=True)
self.show_edit = show_edit
self.show_list = show_list
self.remount_edit_view = remount_edit
self.remount_list_view = remount_list
self.set_selected = set_selected
# TODO: We should use somekind of useState hook here.
@ -98,7 +102,7 @@ class ClanList(Gtk.Box):
# self.list_store.set_value(self.list_store.get_iter(path), 3, "new value")
# self.list_store[path][3] = "new_value"
# This class needs to take ownership of the data because it has access to the listStore only
self.selected_vm: VMBase | None = None
self.selected_vm: VMBase | None = selected_vm
button_hooks = {
"on_start_clicked": self.on_start_clicked,
@ -106,27 +110,27 @@ class ClanList(Gtk.Box):
"on_edit_clicked": self.on_edit_clicked,
}
self.toolbar = ClanListToolbar(**button_hooks)
self.toolbar.set_is_selected(False)
self.toolbar.set_is_selected(self.selected_vm is not None)
self.add(self.toolbar)
self.list_hooks = {
"on_select_row": self.on_select_vm,
}
self.add(ClanListView(**self.list_hooks))
self.add(ClanListView(**self.list_hooks, selected_vm=selected_vm))
def on_start_clicked(self, widget: Gtk.Widget) -> None:
print("Start clicked")
if self.selected_vm:
self.selected_vm.run()
# Call this to reload
self.show_list()
self.remount_list_view()
def on_stop_clicked(self, widget: Gtk.Widget) -> None:
print("Stop clicked")
def on_edit_clicked(self, widget: Gtk.Widget) -> None:
print("Edit clicked")
self.show_edit()
self.remount_edit_view()
def on_select_vm(self, vm: VMBase) -> None:
print(f"on_select_vm: {vm}")
@ -186,9 +190,8 @@ class ClanListView(Gtk.Box):
def __init__(
self,
*,
# vms: list[VMBase],
on_select_row: Callable[[VMBase], None],
# on_double_click: Callable[[VMBase], None],
selected_vm: VMBase | None,
) -> None:
super().__init__(expand=True)
self.vms: list[VMBase] = [vm.base for vm in get_initial_vms()]
@ -202,6 +205,7 @@ class ClanListView(Gtk.Box):
setColRenderers(self.tree_view)
self.set_selected_vm(selected_vm)
selection = self.tree_view.get_selection()
selection.connect("changed", self._on_select_row)
self.tree_view.connect("row-activated", self._on_double_click)
@ -209,6 +213,20 @@ class ClanListView(Gtk.Box):
self.set_border_width(10)
self.add(self.tree_view)
def find_vm(self, vm: VMBase) -> int:
for idx, row in enumerate(self.list_store):
if row[1] == vm.name: # TODO: Change to path
return idx
return -1
def set_selected_vm(self, vm: VMBase | None) -> None:
if vm is None:
return
selection = self.tree_view.get_selection()
idx = self.find_vm(vm)
print(f"Set selected vm: {vm.name} at {idx}")
selection.select_path(idx)
def insertVM(self, vm: VMBase) -> None:
values = list(vm.list_data().values())
values[0] = GdkPixbuf.Pixbuf.new_from_file_at_scale(

View File

@ -10,6 +10,7 @@
, gobject-introspection
, clan-cli
, makeDesktopItem
, mypy
, ipdb
}:
let
@ -34,7 +35,7 @@ python3.pkgs.buildPythonApplication {
];
buildInputs = [ spice-gtk gtk3 gnome.adwaita-icon-theme ];
propagatedBuildInputs = [ ipdb pygobject3 clan-cli ];
propagatedBuildInputs = [ mypy ipdb pygobject3 clan-cli ];
# also re-expose dependencies so we test them in CI
passthru.tests = {

View File

@ -21,8 +21,12 @@ no_implicit_optional = true
module = "gi.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "clan_cli.*"
ignore_missing_imports = true
[tool.ruff]
target-version = "py311"
line-length = 88
select = [ "E", "F", "I", "U", "N", "RUF", "ANN", "A" ]
select = [ "E", "F", "I", "N", "RUF", "ANN", "A" ]
ignore = ["E501", "E402", "N802", "ANN101", "ANN401", "A003"]