manager: Simplify row management a bit

Drop the self.rows dict, use more pygobject row[] convenience
helpers, add some helper properties for VM
This commit is contained in:
Cole Robinson 2018-03-17 17:35:04 -04:00
parent 7de9028221
commit 97db1ac18a

View File

@ -107,10 +107,6 @@ class vmmManager(vmmGObjectUI):
vmmGObjectUI.__init__(self, "manager.ui", "vmm-manager") vmmGObjectUI.__init__(self, "manager.ui", "vmm-manager")
self._cleanup_on_app_close() self._cleanup_on_app_close()
# Mapping of rowkey -> tree model rows to
# allow O(1) access instead of O(n)
self.rows = {}
w, h = self.config.get_manager_window_size() w, h = self.config.get_manager_window_size()
self.topwin.set_default_size(w or 550, h or 550) self.topwin.set_default_size(w or 550, h or 550)
self.prev_position = None self.prev_position = None
@ -222,8 +218,6 @@ class vmmManager(vmmGObjectUI):
def _cleanup(self): def _cleanup(self):
self.rows = None
self.diskcol = None self.diskcol = None
self.guestcpucol = None self.guestcpucol = None
self.memcol = None self.memcol = None
@ -417,10 +411,15 @@ class vmmManager(vmmGObjectUI):
model.set_sort_func(COL_NETWORK, self.vmlist_network_usage_sorter) model.set_sort_func(COL_NETWORK, self.vmlist_network_usage_sorter)
model.set_sort_column_id(COL_NAME, Gtk.SortType.ASCENDING) model.set_sort_column_id(COL_NAME, Gtk.SortType.ASCENDING)
################## ##################
# Helper methods # # Helper methods #
################## ##################
@property
def model(self):
return self.widget("vm-list").get_model()
def current_row(self): def current_row(self):
return uiutil.get_list_selected_row(self.widget("vm-list")) return uiutil.get_list_selected_row(self.widget("vm-list"))
@ -431,21 +430,30 @@ class vmmManager(vmmGObjectUI):
return row[ROW_HANDLE] return row[ROW_HANDLE]
def current_conn(self, choose_default=False): def current_conn(self):
row = self.current_row() row = self.current_row()
if row: if not row:
handle = row[ROW_HANDLE] return None
if row[ROW_IS_CONN]: handle = row[ROW_HANDLE]
return handle if row[ROW_IS_CONN]:
return handle.conn return handle
return handle.conn
if choose_default: def get_row(self, conn_or_vm):
# Nothing selected, use first connection row def _walk(rowiter):
vmlist = self.widget("vm-list") while rowiter:
model = vmlist.get_model() row = self.model[rowiter]
for row in model: if row[ROW_HANDLE] == conn_or_vm:
if row[ROW_IS_CONN]: return row
return row[ROW_HANDLE] if self.model.iter_has_child(rowiter):
ret = _walk(self.model.iter_nth_child(rowiter, 0))
if ret:
return ret
rowiter = self.model.iter_next(rowiter)
if not len(self.model):
return None
return _walk(self.model.get_iter_first())
#################### ####################
@ -479,7 +487,7 @@ class vmmManager(vmmGObjectUI):
def show_host(self, _src): def show_host(self, _src):
from .host import vmmHost from .host import vmmHost
conn = self.current_conn(choose_default=True) conn = self.current_conn()
vmmHost.show_instance(self, conn) vmmHost.show_instance(self, conn)
def show_vm(self, _src): def show_vm(self, _src):
@ -562,42 +570,29 @@ class vmmManager(vmmGObjectUI):
# VM add/remove management methods # # VM add/remove management methods #
#################################### ####################################
def vm_row_key(self, vm):
return vm.get_uuid() + ":" + vm.conn.get_uri()
def vm_added(self, conn, connkey): def vm_added(self, conn, connkey):
vm = conn.get_vm(connkey) vm = conn.get_vm(connkey)
if not vm: if not vm:
return return
row_key = self.vm_row_key(vm) vm_row = self._build_row(None, vm)
if row_key in self.rows: conn_row = self.get_row(conn)
return self.model.append(conn_row.iter, vm_row)
row = self._build_row(None, vm)
parent = self.rows[conn.get_uri()].iter
model = self.widget("vm-list").get_model()
_iter = model.append(parent, row)
path = model.get_path(_iter)
self.rows[row_key] = model[path]
vm.connect("state-changed", self.vm_changed) vm.connect("state-changed", self.vm_changed)
vm.connect("resources-sampled", self.vm_row_updated) vm.connect("resources-sampled", self.vm_row_updated)
vm.connect("inspection-changed", self.vm_inspection_changed) vm.connect("inspection-changed", self.vm_inspection_changed)
# Expand a connection when adding a vm to it # Expand a connection when adding a vm to it
self.widget("vm-list").expand_row(model.get_path(parent), False) self.widget("vm-list").expand_row(conn_row.path, False)
def vm_removed(self, conn, connkey): def vm_removed(self, conn, connkey):
vmlist = self.widget("vm-list") parent = self.get_row(conn).iter
model = vmlist.get_model() for rowidx in range(self.model.iter_n_children(parent)):
rowiter = self.model.iter_nth_child(parent, rowidx)
parent = self.rows[conn.get_uri()].iter vm = self.model[rowiter][ROW_HANDLE]
for row in range(model.iter_n_children(parent)):
vm = model[model.iter_nth_child(parent, row)][ROW_HANDLE]
if vm.get_connkey() == connkey: if vm.get_connkey() == connkey:
model.remove(model.iter_nth_child(parent, row)) self.model.remove(rowiter)
del self.rows[self.vm_row_key(vm)]
break break
def _build_conn_hint(self, conn): def _build_conn_hint(self, conn):
@ -667,15 +662,11 @@ class vmmManager(vmmGObjectUI):
def _conn_added(self, _src, conn): def _conn_added(self, _src, conn):
# Make sure error page isn't showing # Make sure error page isn't showing
self.widget("vm-notebook").set_current_page(0) self.widget("vm-notebook").set_current_page(0)
if self.get_row(conn):
if conn.get_uri() in self.rows:
return return
model = self.widget("vm-list").get_model() conn_row = self._build_row(conn, None)
row = self._build_row(conn, None) self.model.append(None, conn_row)
_iter = model.append(None, row)
path = model.get_path(_iter)
self.rows[conn.get_uri()] = model[path]
conn.connect("vm-added", self.vm_added) conn.connect("vm-added", self.vm_added)
conn.connect("vm-removed", self.vm_removed) conn.connect("vm-removed", self.vm_removed)
@ -686,20 +677,19 @@ class vmmManager(vmmGObjectUI):
self.vm_added(conn, vm.get_connkey()) self.vm_added(conn, vm.get_connkey())
def _conn_removed(self, _src, uri): def _conn_removed(self, _src, uri):
model = self.widget("vm-list").get_model() conn_row = None
parent = self.rows[uri].iter for row in self.model:
if row[ROW_IS_CONN] and row[ROW_HANDLE].get_uri() == uri:
if parent is None: conn_row = row
break
if conn_row is None:
return return
child = model.iter_children(parent) child = self.model.iter_children(conn_row.iter)
while child is not None: while child is not None:
del self.rows[self.vm_row_key(model[child][ROW_HANDLE])] self.model.remove(child)
model.remove(child) child = self.model.iter_children(conn_row.iter)
child = model.iter_children(parent) self.model.remove(conn_row.iter)
model.remove(parent)
del self.rows[uri]
############################# #############################
@ -707,13 +697,13 @@ class vmmManager(vmmGObjectUI):
############################# #############################
def vm_row_updated(self, vm): def vm_row_updated(self, vm):
row = self.rows.get(self.vm_row_key(vm), None) row = self.get_row(vm)
if row is None: if row is None:
return return
self.widget("vm-list").get_model().row_changed(row.path, row.iter) self.model.row_changed(row.path, row.iter)
def vm_changed(self, vm): def vm_changed(self, vm):
row = self.rows.get(self.vm_row_key(vm), None) row = self.get_row(vm)
if row is None: if row is None:
return return
@ -739,7 +729,7 @@ class vmmManager(vmmGObjectUI):
self.vm_row_updated(vm) self.vm_row_updated(vm)
def vm_inspection_changed(self, vm): def vm_inspection_changed(self, vm):
row = self.rows.get(self.vm_row_key(vm), None) row = self.get_row(vm)
if row is None: if row is None:
return return
@ -749,30 +739,22 @@ class vmmManager(vmmGObjectUI):
self.vm_row_updated(vm) self.vm_row_updated(vm)
def set_initial_selection(self, uri): def set_initial_selection(self, uri):
vmlist = self.widget("vm-list") """
model = vmlist.get_model() Select the passed URI in the UI. Called from engine.py via
it = model.get_iter_first() cli --connect $URI
selected = None """
while it: sel = self.widget("vm-list").get_selection()
key = model.get_value(it, ROW_HANDLE) for row in self.model:
if not row[ROW_IS_CONN]:
continue
conn = row[ROW_HANDLE]
if key.get_uri() == uri: if conn.get_uri() == uri:
vmlist.get_selection().select_iter(it) sel.select_iter(row.iter)
return return
if not selected:
vmlist.get_selection().select_iter(it)
selected = key
elif key.get_autoconnect() and not selected.get_autoconnect():
vmlist.get_selection().select_iter(it)
selected = key
if not uri:
return
it = model.iter_next(it)
def conn_state_changed(self, conn): def conn_state_changed(self, conn):
row = self.rows[conn.get_uri()] row = self.get_row(conn)
row[ROW_SORT_KEY] = conn.get_pretty_desc() row[ROW_SORT_KEY] = conn.get_pretty_desc()
row[ROW_MARKUP] = self._build_conn_markup(conn, row[ROW_SORT_KEY]) row[ROW_MARKUP] = self._build_conn_markup(conn, row[ROW_SORT_KEY])
row[ROW_IS_CONN_CONNECTED] = not conn.is_disconnected() row[ROW_IS_CONN_CONNECTED] = not conn.is_disconnected()
@ -780,28 +762,22 @@ class vmmManager(vmmGObjectUI):
row[ROW_HINT] = self._build_conn_hint(conn) row[ROW_HINT] = self._build_conn_hint(conn)
if not conn.is_active(): if not conn.is_active():
# Connection went inactive, delete any VM child nodes child = self.model.iter_children(row.iter)
parent = row.iter while child is not None:
if parent is not None: self.model.remove(child)
model = self.widget("vm-list").get_model() child = self.model.iter_children(row.iter)
child = model.iter_children(parent)
while child is not None:
vm = model[child][ROW_HANDLE]
del self.rows[self.vm_row_key(vm)]
model.remove(child)
child = model.iter_children(parent)
self.conn_row_updated(conn) self.conn_row_updated(conn)
self.update_current_selection() self.update_current_selection()
def conn_row_updated(self, conn): def conn_row_updated(self, conn):
row = self.rows[conn.get_uri()] row = self.get_row(conn)
self.max_disk_rate = max(self.max_disk_rate, conn.disk_io_max_rate()) self.max_disk_rate = max(self.max_disk_rate, conn.disk_io_max_rate())
self.max_net_rate = max(self.max_net_rate, self.max_net_rate = max(self.max_net_rate,
conn.network_traffic_max_rate()) conn.network_traffic_max_rate())
self.widget("vm-list").get_model().row_changed(row.path, row.iter) self.model.row_changed(row.path, row.iter)
def change_run_text(self, can_restore): def change_run_text(self, can_restore):
if can_restore: if can_restore:
@ -859,18 +835,16 @@ class vmmManager(vmmGObjectUI):
self.popup_vm_menu(model, treeiter, event) self.popup_vm_menu(model, treeiter, event)
return True return True
def popup_vm_menu_button(self, widget, event): def popup_vm_menu_button(self, vmlist, event):
if event.button != 3: if event.button != 3:
return False return False
tup = widget.get_path_at_pos(int(event.x), int(event.y)) tup = vmlist.get_path_at_pos(int(event.x), int(event.y))
if tup is None: if tup is None:
return False return False
path = tup[0] path = tup[0]
model = widget.get_model()
_iter = model.get_iter(path)
self.popup_vm_menu(model, _iter, event) self.popup_vm_menu(self.model, self.model.get_iter(path), event)
return False return False
def popup_vm_menu(self, model, _iter, event): def popup_vm_menu(self, model, _iter, event):