vm-manager: Added right click context menu

This commit is contained in:
Qubasa
2024-01-02 07:24:30 +01:00
parent 01977b2e2a
commit 7be42146e7
4 changed files with 68 additions and 5 deletions

View File

@@ -9,8 +9,9 @@ from clan_cli.flakes.inspect import FlakeConfig, inspect_flake
from ..clan_uri import ClanURI from ..clan_uri import ClanURI
from ..dirs import user_history_file from ..dirs import user_history_file
from ..locked_open import read_history_file, write_history_file
from ..errors import ClanError from ..errors import ClanError
from ..locked_open import read_history_file, write_history_file
class EnhancedJSONEncoder(json.JSONEncoder): class EnhancedJSONEncoder(json.JSONEncoder):
def default(self, o: Any) -> Any: def default(self, o: Any) -> Any:
@@ -53,7 +54,8 @@ def list_history() -> list[HistoryEntry]:
try: try:
parsed = read_history_file() parsed = read_history_file()
for i, p in enumerate(parsed.copy()): for i, p in enumerate(parsed.copy()):
parsed[i] = merge_dicts(p, p["settings"]) # Everything from the settings dict is merged into the flake dict, and can override existing values
parsed[i] = merge_dicts(p, p.get("settings", {}))
logs = [HistoryEntry(**p) for p in parsed] logs = [HistoryEntry(**p) for p in parsed]
except (json.JSONDecodeError, TypeError) as ex: except (json.JSONDecodeError, TypeError) as ex:
raise ClanError(f"History file at {user_history_file()} is corrupted") from ex raise ClanError(f"History file at {user_history_file()} is corrupted") from ex

View File

@@ -10,6 +10,7 @@ from .errors.show_error import show_error_dialog
gi.require_version("GdkPixbuf", "2.0") gi.require_version("GdkPixbuf", "2.0")
from clan_cli.errors import ClanError
from gi.repository import GdkPixbuf from gi.repository import GdkPixbuf
from clan_vm_manager import assets from clan_vm_manager import assets
@@ -60,6 +61,7 @@ class VM:
description: str | None = None description: str | None = None
# TODO: How to handle incompatible / corrupted history file. Delete it?
# start/end indexes can be used optionally for pagination # start/end indexes can be used optionally for pagination
def get_initial_vms( def get_initial_vms(
running_vms: list[str], start: int = 0, end: int | None = None running_vms: list[str], start: int = 0, end: int | None = None
@@ -85,7 +87,7 @@ def get_initial_vms(
_flake_attr=entry.flake.flake_attr, _flake_attr=entry.flake.flake_attr,
) )
vm_list.append(VM(base=base)) vm_list.append(VM(base=base))
except Exception as e: except ClanError as e:
show_error_dialog(e) show_error_dialog(e)
# start/end slices can be used for pagination # start/end slices can be used for pagination

View File

@@ -1,9 +1,10 @@
from collections.abc import Callable from collections.abc import Callable
from gi.repository import GdkPixbuf, Gtk from gi.repository import Gdk, GdkPixbuf, Gtk
from ..interfaces import Callbacks from ..interfaces import Callbacks
from ..models import VMBase from ..models import VMBase
from .context_menu import VmMenu
class ClanEditForm(Gtk.ListBox): class ClanEditForm(Gtk.ListBox):
@@ -97,7 +98,6 @@ class ClanList(Gtk.Box):
self.set_selected = set_selected self.set_selected = set_selected
self.show_toolbar = show_toolbar self.show_toolbar = show_toolbar
self.cbs = cbs self.cbs = cbs
self.show_join = cbs.show_join self.show_join = cbs.show_join
self.selected_vm: VMBase | None = selected_vm self.selected_vm: VMBase | None = selected_vm
@@ -228,6 +228,8 @@ class ClanListView(Gtk.Box):
self.vms: list[VMBase] = vms self.vms: list[VMBase] = vms
self.on_select_row = on_select_row self.on_select_row = on_select_row
self.on_double_click = on_double_click self.on_double_click = on_double_click
self.context_menu: VmMenu | None = None
store_types = VMBase.name_to_type_map().values() store_types = VMBase.name_to_type_map().values()
self.list_store = Gtk.ListStore(*store_types) self.list_store = Gtk.ListStore(*store_types)
@@ -241,6 +243,7 @@ class ClanListView(Gtk.Box):
selection = self.tree_view.get_selection() selection = self.tree_view.get_selection()
selection.connect("changed", self._on_select_row) selection.connect("changed", self._on_select_row)
self.tree_view.connect("row-activated", self._on_double_click) self.tree_view.connect("row-activated", self._on_double_click)
self.tree_view.connect("button-press-event", self._on_button_pressed)
self.set_border_width(10) self.set_border_width(10)
self.add(self.tree_view) self.add(self.tree_view)
@@ -272,12 +275,29 @@ class ClanListView(Gtk.Box):
vm = VMBase(*model[row]) vm = VMBase(*model[row])
self.on_select_row(vm) self.on_select_row(vm)
def _on_button_pressed(
self, tree_view: Gtk.TreeView, event: Gdk.EventButton
) -> None:
if self.context_menu:
self.context_menu.destroy()
self.context_menu = None
if event.button == 3:
path, column, x, y = tree_view.get_path_at_pos(event.x, event.y)
if path is not None:
vm = VMBase(*self.list_store[path[0]])
print(event)
print(f"Right click on {vm.url}")
self.context_menu = VmMenu(vm)
self.context_menu.popup_at_pointer(event)
def _on_double_click( def _on_double_click(
self, tree_view: Gtk.TreeView, path: Gtk.TreePath, column: Gtk.TreeViewColumn self, tree_view: Gtk.TreeView, path: Gtk.TreePath, column: Gtk.TreeViewColumn
) -> None: ) -> None:
# Get the selection object of the tree view # Get the selection object of the tree view
selection = tree_view.get_selection() selection = tree_view.get_selection()
model, row = selection.get_selected() model, row = selection.get_selected()
if row is not None: if row is not None:
vm = VMBase(*model[row]) vm = VMBase(*model[row])
self.on_double_click(vm) self.on_double_click(vm)

View File

@@ -0,0 +1,39 @@
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
from ..models import VMBase
class VmMenu(Gtk.Menu):
def __init__(self, vm: VMBase) -> None:
super().__init__()
self.vm = vm
self.menu_items = [
("Start", self.start_vm),
("Stop", self.stop_vm),
("Edit", self.edit_vm),
("Remove", self.remove_vm),
("Write to USB", self.write_to_usb),
]
for item in self.menu_items:
menu_item = Gtk.MenuItem(label=item[0])
menu_item.connect("activate", item[1])
self.append(menu_item)
self.show_all()
def start_vm(self, widget: Gtk.Widget) -> None:
print("start_vm")
def stop_vm(self, widget: Gtk.Widget) -> None:
print("stop_vm")
def edit_vm(self, widget: Gtk.Widget) -> None:
print("edit_vm")
def remove_vm(self, widget: Gtk.Widget) -> None:
print("remove_vm")
def write_to_usb(self, widget: Gtk.Widget) -> None:
print("write_to_usb")