vm-manager: Added right click context menu
This commit is contained in:
@@ -9,8 +9,9 @@ from clan_cli.flakes.inspect import FlakeConfig, inspect_flake
|
||||
|
||||
from ..clan_uri import ClanURI
|
||||
from ..dirs import user_history_file
|
||||
from ..locked_open import read_history_file, write_history_file
|
||||
from ..errors import ClanError
|
||||
from ..locked_open import read_history_file, write_history_file
|
||||
|
||||
|
||||
class EnhancedJSONEncoder(json.JSONEncoder):
|
||||
def default(self, o: Any) -> Any:
|
||||
@@ -53,7 +54,8 @@ def list_history() -> list[HistoryEntry]:
|
||||
try:
|
||||
parsed = read_history_file()
|
||||
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]
|
||||
except (json.JSONDecodeError, TypeError) as ex:
|
||||
raise ClanError(f"History file at {user_history_file()} is corrupted") from ex
|
||||
|
||||
@@ -10,6 +10,7 @@ from .errors.show_error import show_error_dialog
|
||||
|
||||
gi.require_version("GdkPixbuf", "2.0")
|
||||
|
||||
from clan_cli.errors import ClanError
|
||||
from gi.repository import GdkPixbuf
|
||||
|
||||
from clan_vm_manager import assets
|
||||
@@ -60,6 +61,7 @@ class VM:
|
||||
description: str | None = None
|
||||
|
||||
|
||||
# TODO: How to handle incompatible / corrupted history file. Delete it?
|
||||
# start/end indexes can be used optionally for pagination
|
||||
def get_initial_vms(
|
||||
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,
|
||||
)
|
||||
vm_list.append(VM(base=base))
|
||||
except Exception as e:
|
||||
except ClanError as e:
|
||||
show_error_dialog(e)
|
||||
|
||||
# start/end slices can be used for pagination
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
from collections.abc import Callable
|
||||
|
||||
from gi.repository import GdkPixbuf, Gtk
|
||||
from gi.repository import Gdk, GdkPixbuf, Gtk
|
||||
|
||||
from ..interfaces import Callbacks
|
||||
from ..models import VMBase
|
||||
from .context_menu import VmMenu
|
||||
|
||||
|
||||
class ClanEditForm(Gtk.ListBox):
|
||||
@@ -97,7 +98,6 @@ class ClanList(Gtk.Box):
|
||||
self.set_selected = set_selected
|
||||
self.show_toolbar = show_toolbar
|
||||
self.cbs = cbs
|
||||
|
||||
self.show_join = cbs.show_join
|
||||
|
||||
self.selected_vm: VMBase | None = selected_vm
|
||||
@@ -228,6 +228,8 @@ class ClanListView(Gtk.Box):
|
||||
self.vms: list[VMBase] = vms
|
||||
self.on_select_row = on_select_row
|
||||
self.on_double_click = on_double_click
|
||||
self.context_menu: VmMenu | None = None
|
||||
|
||||
store_types = VMBase.name_to_type_map().values()
|
||||
|
||||
self.list_store = Gtk.ListStore(*store_types)
|
||||
@@ -241,6 +243,7 @@ class ClanListView(Gtk.Box):
|
||||
selection = self.tree_view.get_selection()
|
||||
selection.connect("changed", self._on_select_row)
|
||||
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.add(self.tree_view)
|
||||
@@ -272,12 +275,29 @@ class ClanListView(Gtk.Box):
|
||||
vm = VMBase(*model[row])
|
||||
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(
|
||||
self, tree_view: Gtk.TreeView, path: Gtk.TreePath, column: Gtk.TreeViewColumn
|
||||
) -> None:
|
||||
# Get the selection object of the tree view
|
||||
selection = tree_view.get_selection()
|
||||
model, row = selection.get_selected()
|
||||
|
||||
if row is not None:
|
||||
vm = VMBase(*model[row])
|
||||
self.on_double_click(vm)
|
||||
|
||||
39
pkgs/clan-vm-manager/clan_vm_manager/ui/context_menu.py
Normal file
39
pkgs/clan-vm-manager/clan_vm_manager/ui/context_menu.py
Normal 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")
|
||||
Reference in New Issue
Block a user