be94c87f61
It seems that when sort is reversed, dom0 gets sorted last. This is expected and hard to counter. Will remain for now.
726 lines
24 KiB
Python
726 lines
24 KiB
Python
#!/usr/bin/python2
|
|
# -*- coding: utf8 -*-
|
|
#
|
|
# The Qubes OS Project, http://www.qubes-os.org
|
|
#
|
|
# Copyright (C) 2014 Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
import os
|
|
|
|
from PyQt4 import QtGui
|
|
|
|
from PyQt4.QtCore import QSize, Qt
|
|
|
|
from PyQt4.QtGui import QTableWidgetItem, QHBoxLayout, QIcon, QLabel, QWidget, \
|
|
QSizePolicy, QSpacerItem, QFont, QColor, QProgressBar, QPainter, QPen
|
|
import time
|
|
from qubes.qubes import vm_files
|
|
import main
|
|
|
|
qubes_dom0_updates_stat_file = '/var/lib/qubes/updates/dom0-updates-available'
|
|
power_order = Qt.DescendingOrder
|
|
update_order = Qt.AscendingOrder
|
|
|
|
|
|
row_height = 30
|
|
|
|
|
|
class VmIconWidget (QWidget):
|
|
def __init__(self, icon_path, enabled=True, size_multiplier=0.7,
|
|
tooltip = None, parent=None, icon_sz = (32, 32)):
|
|
super(VmIconWidget, self).__init__(parent)
|
|
|
|
self.label_icon = QLabel()
|
|
if icon_path[0] in ':/':
|
|
icon = QIcon (icon_path)
|
|
else:
|
|
icon = QIcon.fromTheme(icon_path)
|
|
icon_sz = QSize (row_height * size_multiplier, row_height * size_multiplier)
|
|
icon_pixmap = icon.pixmap(icon_sz, QIcon.Disabled if not enabled else QIcon.Normal)
|
|
self.label_icon.setPixmap (icon_pixmap)
|
|
self.label_icon.setFixedSize (icon_sz)
|
|
if tooltip != None:
|
|
self.label_icon.setToolTip(tooltip)
|
|
|
|
layout = QHBoxLayout()
|
|
layout.addWidget(self.label_icon)
|
|
layout.setContentsMargins(0,0,0,0)
|
|
self.setLayout(layout)
|
|
|
|
def setToolTip(self, tooltip):
|
|
if tooltip is not None:
|
|
self.label_icon.setToolTip(tooltip)
|
|
else:
|
|
self.label_icon.setToolTip('')
|
|
|
|
class VmTypeWidget(VmIconWidget):
|
|
|
|
class VmTypeItem(QTableWidgetItem):
|
|
def __init__(self, value, vm):
|
|
super(VmTypeWidget.VmTypeItem, self).__init__()
|
|
self.value = value
|
|
self.vm = vm
|
|
|
|
def set_value(self, value):
|
|
self.value = value
|
|
|
|
def __lt__(self, other):
|
|
if self.vm.qid == 0:
|
|
return True
|
|
elif other.vm.qid == 0:
|
|
return False
|
|
elif self.value == other.value:
|
|
return self.vm.qid < other.vm.qid
|
|
else:
|
|
return self.value < other.value
|
|
|
|
def __init__(self, vm, parent=None):
|
|
(icon_path, tooltip) = self.get_vm_icon(vm)
|
|
super (VmTypeWidget, self).__init__(icon_path, True, 0.8, tooltip, parent)
|
|
self.vm = vm
|
|
self.tableItem = self.VmTypeItem(self.value, vm)
|
|
|
|
def get_vm_icon(self, vm):
|
|
if vm.qid == 0:
|
|
self.value = 0
|
|
return (":/dom0.png", "Dom0")
|
|
elif vm.is_netvm() and not vm.is_proxyvm():
|
|
self.value = 1
|
|
return (":/netvm.png", "NetVM")
|
|
elif vm.is_proxyvm():
|
|
self.value = 2
|
|
return (":/proxyvm.png", "ProxyVM")
|
|
elif vm.is_appvm() and vm.template is None:
|
|
self.value = 4
|
|
return (":/standalonevm.png", "StandaloneVM")
|
|
elif vm.is_template():
|
|
self.value = 3
|
|
return (":/templatevm.png", "TemplateVM")
|
|
elif vm.is_appvm() or vm.is_disposablevm():
|
|
self.value = 5 + vm.label.index
|
|
return (":/appvm.png", "AppVM")
|
|
|
|
|
|
class VmLabelWidget(VmIconWidget):
|
|
|
|
class VmLabelItem(QTableWidgetItem):
|
|
def __init__(self, value, vm):
|
|
super(VmLabelWidget.VmLabelItem, self).__init__()
|
|
self.value = value
|
|
self.vm = vm
|
|
|
|
def set_value(self, value):
|
|
self.value = value
|
|
|
|
def __lt__(self, other):
|
|
if self.vm.qid == 0:
|
|
return True
|
|
elif other.vm.qid == 0:
|
|
return False
|
|
elif self.value == other.value:
|
|
return self.vm.qid < other.vm.qid
|
|
else:
|
|
return self.value < other.value
|
|
|
|
def __init__(self, vm, parent=None):
|
|
icon_path = self.get_vm_icon_path(vm)
|
|
super (VmLabelWidget, self).__init__(icon_path, True, 0.8, None, parent)
|
|
self.vm = vm
|
|
self.tableItem = self.VmLabelItem(self.value, vm)
|
|
|
|
def get_vm_icon_path(self, vm):
|
|
if vm.qid == 0:
|
|
self.value = 100
|
|
return ":/off.png"
|
|
else:
|
|
self.value = vm.label.index
|
|
return vm.label.icon
|
|
|
|
|
|
|
|
class VmNameItem (QTableWidgetItem):
|
|
def __init__(self, vm):
|
|
super(VmNameItem, self).__init__()
|
|
self.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled)
|
|
self.setText(vm.name)
|
|
self.setTextAlignment(Qt.AlignVCenter)
|
|
self.qid = vm.qid
|
|
|
|
def __lt__(self, other):
|
|
if self.qid == 0:
|
|
return True
|
|
elif other.qid == 0:
|
|
return False
|
|
return super(VmNameItem, self).__lt__(other)
|
|
|
|
|
|
class VmStatusIcon(QLabel):
|
|
def __init__(self, vm, parent=None):
|
|
super (VmStatusIcon, self).__init__(parent)
|
|
self.vm = vm
|
|
self.set_on_icon()
|
|
self.previous_power_state = vm.last_power_state
|
|
|
|
def update(self):
|
|
if self.previous_power_state != self.vm.last_power_state:
|
|
self.set_on_icon()
|
|
self.previous_power_state = self.vm.last_power_state
|
|
|
|
def set_on_icon(self):
|
|
if self.vm.last_power_state == "Running":
|
|
icon = QIcon (":/on.png")
|
|
elif self.vm.last_power_state in ["Paused"]:
|
|
icon = QIcon (":/paused.png")
|
|
elif self.vm.last_power_state in ["Transient", "Halting", "Dying"]:
|
|
icon = QIcon (":/transient.png")
|
|
else:
|
|
icon = QIcon (":/off.png")
|
|
|
|
icon_sz = QSize (row_height * 0.5, row_height *0.5)
|
|
icon_pixmap = icon.pixmap(icon_sz)
|
|
self.setPixmap (icon_pixmap)
|
|
self.setFixedSize (icon_sz)
|
|
|
|
|
|
|
|
class VmInfoWidget (QWidget):
|
|
|
|
class VmInfoItem (QTableWidgetItem):
|
|
def __init__(self, upd_info_item, vm):
|
|
super(VmInfoWidget.VmInfoItem, self).__init__()
|
|
self.upd_info_item = upd_info_item
|
|
self.vm = vm
|
|
|
|
def __lt__(self, other):
|
|
if self.vm.qid == 0:
|
|
return True
|
|
elif other.vm.qid == 0:
|
|
return False
|
|
|
|
self_val = self.upd_info_item.value
|
|
other_val = other.upd_info_item.value
|
|
if self.tableWidget().horizontalHeader().sortIndicatorOrder() == update_order:
|
|
# the result will be sorted by upd, sorting order: Ascending
|
|
self_val += 1 if self.vm.is_running() else 0
|
|
other_val += 1 if other.vm.is_running() else 0
|
|
if self_val == other_val:
|
|
return self.vm.qid < other.vm.qid
|
|
else:
|
|
return self_val > other_val
|
|
elif self.tableWidget().horizontalHeader().sortIndicatorOrder() == power_order:
|
|
#the result will be sorted by power state, sorting order: Descending
|
|
self_val = -(self_val/10 + 10*(1 if self.vm.is_running() else 0))
|
|
other_val = -(other_val/10 + 10*(1 if other.vm.is_running() else 0))
|
|
if self_val == other_val:
|
|
return self.vm.qid < other.vm.qid
|
|
else:
|
|
return self_val > other_val
|
|
else:
|
|
#it would be strange if this happened
|
|
return
|
|
|
|
def __init__(self, vm, parent = None):
|
|
super (VmInfoWidget, self).__init__(parent)
|
|
self.vm = vm
|
|
layout = QHBoxLayout ()
|
|
|
|
self.on_icon = VmStatusIcon(vm)
|
|
self.upd_info = VmUpdateInfoWidget(vm, show_text=False)
|
|
self.error_icon = VmIconWidget(":/warning.png")
|
|
self.blk_icon = VmIconWidget(":/mount.png")
|
|
self.rec_icon = VmIconWidget(":/mic.png")
|
|
|
|
layout.addWidget(self.on_icon)
|
|
layout.addWidget(self.upd_info)
|
|
layout.addWidget(self.error_icon)
|
|
layout.addItem(QSpacerItem(0, 10, QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding))
|
|
layout.addWidget(self.blk_icon)
|
|
layout.addWidget(self.rec_icon)
|
|
|
|
layout.setContentsMargins(5,0,5,0)
|
|
self.setLayout(layout)
|
|
|
|
self.rec_icon.setVisible(False)
|
|
self.blk_icon.setVisible(False)
|
|
self.error_icon.setVisible(False)
|
|
|
|
self.tableItem = self.VmInfoItem(self.upd_info.tableItem, vm)
|
|
|
|
def update_vm_state(self, vm, blk_visible, rec_visible=None):
|
|
self.on_icon.update()
|
|
self.upd_info.update_outdated(vm)
|
|
if blk_visible != None:
|
|
self.blk_icon.setVisible(blk_visible)
|
|
if rec_visible != None:
|
|
self.rec_icon.setVisible(rec_visible)
|
|
self.error_icon.setToolTip(vm.qubes_manager_state[main.QMVmState
|
|
.ErrorMsg])
|
|
self.error_icon.setVisible(vm.qubes_manager_state[main.QMVmState
|
|
.ErrorMsg] is not None)
|
|
|
|
|
|
class VmTemplateItem (QTableWidgetItem):
|
|
def __init__(self, vm):
|
|
super(VmTemplateItem, self).__init__()
|
|
self.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled)
|
|
self.vm = vm
|
|
|
|
if vm.template is not None:
|
|
self.setText(vm.template.name)
|
|
else:
|
|
font = QFont()
|
|
font.setStyle(QFont.StyleItalic)
|
|
self.setFont(font)
|
|
self.setTextColor(QColor("gray"))
|
|
|
|
if vm.is_appvm(): # and vm.template is None
|
|
self.setText("StandaloneVM")
|
|
elif vm.is_template():
|
|
self.setText("TemplateVM")
|
|
elif vm.qid == 0:
|
|
self.setText("AdminVM")
|
|
elif vm.is_netvm():
|
|
self.setText("NetVM")
|
|
else:
|
|
self.setText("---")
|
|
|
|
self.setTextAlignment(Qt.AlignVCenter)
|
|
|
|
def __lt__(self, other):
|
|
if self.vm.qid == 0:
|
|
return True
|
|
elif other.vm.qid == 0:
|
|
return False
|
|
elif self.text() == other.text():
|
|
return self.vm.qid < other.vm.qid
|
|
else:
|
|
return super(VmTemplateItem, self).__lt__(other)
|
|
|
|
|
|
|
|
|
|
class VmNetvmItem (QTableWidgetItem):
|
|
def __init__(self, vm):
|
|
super(VmNetvmItem, self).__init__()
|
|
self.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled)
|
|
self.vm = vm
|
|
|
|
if vm.is_netvm() and not vm.is_proxyvm():
|
|
self.setText("n/a")
|
|
elif vm.netvm is not None:
|
|
self.setText(vm.netvm.name)
|
|
else:
|
|
self.setText("---")
|
|
|
|
self.setTextAlignment(Qt.AlignVCenter)
|
|
|
|
def __lt__(self, other):
|
|
if self.vm.qid == 0:
|
|
return True
|
|
elif other.vm.qid == 0:
|
|
return False
|
|
elif self.text() == other.text():
|
|
return self.vm.qid < other.vm.qid
|
|
else:
|
|
return super(VmNetvmItem, self).__lt__(other)
|
|
|
|
class VmInternalItem(QTableWidgetItem):
|
|
def __init__(self, vm):
|
|
super(VmInternalItem, self).__init__()
|
|
self.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled)
|
|
|
|
self.vm = vm
|
|
self.internal = self.vm.internal
|
|
|
|
if self.internal:
|
|
self.setText("Yes")
|
|
else:
|
|
self.setText("")
|
|
|
|
def __lt__(self, other):
|
|
if self.vm.qid == 0:
|
|
return True
|
|
elif other.vm.qid == 0:
|
|
return False
|
|
return super(VmInternalItem, self).__lt__(other)
|
|
|
|
|
|
class VmUsageBarWidget (QWidget):
|
|
|
|
class VmUsageBarItem (QTableWidgetItem):
|
|
def __init__(self, value, vm):
|
|
super(VmUsageBarWidget.VmUsageBarItem, self).__init__()
|
|
self.value = value
|
|
self.vm = vm
|
|
|
|
def set_value(self, value):
|
|
self.value = value
|
|
|
|
def __lt__(self, other):
|
|
if self.vm.qid == 0:
|
|
return True
|
|
elif other.vm.qid == 0:
|
|
return False
|
|
elif self.value == other.value:
|
|
return self.vm.qid < other.vm.qid
|
|
else:
|
|
return int(self.value) < int(other.value)
|
|
|
|
def __init__(self, min, max, format, update_func, vm, load, hue=210, parent = None):
|
|
super (VmUsageBarWidget, self).__init__(parent)
|
|
|
|
|
|
self.min = min
|
|
self.max = max
|
|
self.update_func = update_func
|
|
self.value = min
|
|
|
|
self.widget = QProgressBar()
|
|
self.widget.setMinimum(min)
|
|
self.widget.setMaximum(max)
|
|
self.widget.setFormat(format)
|
|
|
|
self.widget.setStyleSheet(
|
|
"QProgressBar:horizontal{" +\
|
|
"border: 1px solid hsv({0}, 100, 250);".format(hue) +\
|
|
"border-radius: 4px;\
|
|
background: white;\
|
|
text-align: center;\
|
|
}\
|
|
QProgressBar::chunk:horizontal {\
|
|
background: qlineargradient(x1: 0, y1: 0.5, x2: 1, y2: 0.5, " +\
|
|
"stop: 0 hsv({0}, 170, 207),".format(hue) +
|
|
" stop: 1 white); \
|
|
}"
|
|
)
|
|
|
|
layout = QHBoxLayout()
|
|
layout.addWidget(self.widget)
|
|
|
|
self.setLayout(layout)
|
|
self.tableItem = self.VmUsageBarItem(min, vm)
|
|
|
|
self.update_load(vm, load)
|
|
|
|
|
|
|
|
def update_load(self, vm, load):
|
|
self.value = self.update_func(vm, load)
|
|
self.widget.setValue(self.value)
|
|
self.tableItem.set_value(self.value)
|
|
|
|
class ChartWidget (QWidget):
|
|
|
|
class ChartItem (QTableWidgetItem):
|
|
def __init__(self, value, vm):
|
|
super(ChartWidget.ChartItem, self).__init__()
|
|
self.value = value
|
|
self.vm = vm
|
|
|
|
def set_value(self, value):
|
|
self.value = value
|
|
|
|
def __lt__(self, other):
|
|
if self.vm.qid == 0:
|
|
return True
|
|
elif other.vm.qid == 0:
|
|
return False
|
|
elif self.value == other.value:
|
|
return self.vm.qid < other.vm.qid
|
|
else:
|
|
return self.value < other.value
|
|
|
|
def __init__(self, vm, update_func, hue, load = 0, parent = None):
|
|
super (ChartWidget, self).__init__(parent)
|
|
self.update_func = update_func
|
|
self.hue = hue
|
|
if hue < 0 or hue > 255:
|
|
self.hue = 255
|
|
self.load = load
|
|
assert self.load >= 0 and self.load <= 100, "load = {0}".format(self.load)
|
|
self.load_history = [self.load]
|
|
self.tableItem = ChartWidget.ChartItem(self.load, vm)
|
|
|
|
def update_load (self, vm, load):
|
|
self.load = self.update_func(vm, load)
|
|
|
|
assert self.load >= 0, "load = {0}".format(self.load)
|
|
# assert self.load >= 0 and self.load <= 100, "load = {0}".format(self.load)
|
|
if self.load > 100:
|
|
# FIXME: This is an ugly workaround for cpu_load:/
|
|
self.load = 100
|
|
|
|
self.load_history.append (self.load)
|
|
self.tableItem.set_value(self.load)
|
|
self.repaint()
|
|
|
|
def paintEvent (self, Event = None):
|
|
p = QPainter (self)
|
|
dx = 4
|
|
|
|
W = self.width()
|
|
H = self.height() - 5
|
|
N = len(self.load_history)
|
|
if N > W/dx:
|
|
tail = N - W/dx
|
|
N = W/dx
|
|
self.load_history = self.load_history[tail:]
|
|
|
|
assert len(self.load_history) == N
|
|
|
|
for i in range (0, N-1):
|
|
val = self.load_history[N- i - 1]
|
|
sat = 70 + val*(255-70)/100
|
|
color = QColor.fromHsv (self.hue, sat, 255)
|
|
pen = QPen (color)
|
|
pen.setWidth(dx-1)
|
|
p.setPen(pen)
|
|
if val > 0:
|
|
p.drawLine (W - i*dx - dx, H , W - i*dx - dx, H - (H - 5) * val/100)
|
|
|
|
|
|
|
|
class VmUpdateInfoWidget(QWidget):
|
|
|
|
class VmUpdateInfoItem (QTableWidgetItem):
|
|
def __init__(self, value, vm):
|
|
super(VmUpdateInfoWidget.VmUpdateInfoItem, self).__init__()
|
|
self.value = 0
|
|
self.vm = vm
|
|
self.set_value(value)
|
|
|
|
def set_value(self, value):
|
|
if value in ("outdated", "to-be-outdated"):
|
|
self.value = 30
|
|
elif value == "update":
|
|
self.value = 20
|
|
else:
|
|
self.value = 0
|
|
|
|
def __lt__(self, other):
|
|
if self.vm.qid == 0:
|
|
return True
|
|
elif other.vm.qid == 0:
|
|
return False
|
|
elif self.value == other.value:
|
|
return self.vm.qid < other.vm.qid
|
|
else:
|
|
return self.value < other.value
|
|
|
|
def __init__(self, vm, show_text=True, parent = None):
|
|
super (VmUpdateInfoWidget, self).__init__(parent)
|
|
layout = QHBoxLayout ()
|
|
self.show_text = show_text
|
|
if self.show_text:
|
|
self.label=QLabel("")
|
|
layout.addWidget(self.label, alignment=Qt.AlignCenter)
|
|
else:
|
|
self.icon = QLabel("")
|
|
layout.addWidget(self.icon, alignment=Qt.AlignCenter)
|
|
self.setLayout(layout)
|
|
|
|
self.previous_outdated_state = None
|
|
self.previous_update_recommended = None
|
|
self.value = None
|
|
self.tableItem = VmUpdateInfoWidget.VmUpdateInfoItem(self.value, vm)
|
|
|
|
def update_outdated(self, vm):
|
|
if vm.type == "HVM":
|
|
return
|
|
|
|
if vm.is_outdated():
|
|
outdated_state = "outdated"
|
|
# During TemplateVM shutdown, there's an interval of a few seconds
|
|
# during which vm.template.is_running() returns false but
|
|
# vm.is_outdated() does not yet return true, so the icon disappears.
|
|
# This looks goofy, but we've decided not to fix it at this time
|
|
# (2015-02-09).
|
|
elif vm.template and vm.template.is_running():
|
|
outdated_state = "to-be-outdated"
|
|
else:
|
|
outdated_state = None
|
|
|
|
if outdated_state != self.previous_outdated_state:
|
|
self.update_status_widget(outdated_state)
|
|
|
|
self.previous_outdated_state = outdated_state
|
|
|
|
if not vm.is_updateable():
|
|
return
|
|
|
|
if vm.qid == 0:
|
|
update_recommended = self.previous_update_recommended
|
|
if os.path.exists(qubes_dom0_updates_stat_file):
|
|
update_recommended = True
|
|
else:
|
|
update_recommended = False
|
|
|
|
else:
|
|
update_recommended = self.previous_update_recommended
|
|
stat_file_path = vm.dir_path + '/' + vm_files["updates_stat_file"]
|
|
if not os.path.exists(stat_file_path):
|
|
update_recommended = False
|
|
else:
|
|
if (not hasattr(vm, "updates_stat_file_read_time")) or vm.updates_stat_file_read_time <= os.path.getmtime(stat_file_path):
|
|
|
|
stat_file = open(stat_file_path, "r")
|
|
updates = stat_file.read().strip()
|
|
stat_file.close()
|
|
if updates.isdigit():
|
|
updates = int(updates)
|
|
else:
|
|
updates = 0
|
|
|
|
if updates == 0:
|
|
update_recommended = False
|
|
else:
|
|
update_recommended = True
|
|
vm.updates_stat_file_read_time = time.time()
|
|
|
|
if update_recommended and not self.previous_update_recommended:
|
|
self.update_status_widget("update")
|
|
elif self.previous_update_recommended and not update_recommended:
|
|
self.update_status_widget(None)
|
|
|
|
self.previous_update_recommended = update_recommended
|
|
|
|
|
|
def update_status_widget(self, state):
|
|
self.value = state
|
|
self.tableItem.set_value(state)
|
|
if state == "update":
|
|
label_text = "<font color=\"#CCCC00\">Check updates</font>"
|
|
icon_path = ":/update-recommended.png"
|
|
tooltip_text = "Updates pending!"
|
|
elif state == "outdated":
|
|
label_text = "<font color=\"red\">VM outdated</font>"
|
|
icon_path = ":/outdated.png"
|
|
tooltip_text = "The VM must be restarted for its filesystem to reflect the template's recent committed changes."
|
|
elif state == "to-be-outdated":
|
|
label_text = "<font color=\"#800000\">TemplateVM running</font>"
|
|
icon_path = ":/to-be-outdated.png"
|
|
tooltip_text = "The TemplateVM must be stopped before changes from its current session can be picked up by this VM."
|
|
elif state == None:
|
|
label_text = ""
|
|
icon_path = None
|
|
tooltip_text = None
|
|
|
|
if self.show_text:
|
|
self.label.setText(label_text)
|
|
else:
|
|
self.layout().removeWidget(self.icon)
|
|
self.icon.deleteLater()
|
|
if icon_path != None:
|
|
self.icon = VmIconWidget(icon_path, True, 0.7)
|
|
self.icon.setToolTip(tooltip_text)
|
|
else:
|
|
self.icon = QLabel(label_text)
|
|
self.layout().addWidget(self.icon, alignment=Qt.AlignCenter)
|
|
|
|
|
|
class VmSizeOnDiskItem (QTableWidgetItem):
|
|
def __init__(self, vm):
|
|
super(VmSizeOnDiskItem, self).__init__()
|
|
self.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled)
|
|
|
|
self.vm = vm
|
|
self.value = 0
|
|
self.update()
|
|
self.setTextAlignment(Qt.AlignVCenter)
|
|
|
|
def update(self):
|
|
if self.vm.qid == 0:
|
|
self.setText("n/a")
|
|
else:
|
|
self.value = self.vm.get_disk_utilization()/(1024*1024)
|
|
self.setText( str(self.value) + " MiB")
|
|
|
|
def __lt__(self, other):
|
|
if self.vm.qid == 0:
|
|
return True
|
|
elif other.vm.qid == 0:
|
|
return False
|
|
elif self.value == other.value:
|
|
return self.vm.qid < other.vm.qid
|
|
else:
|
|
return self.value < other.value
|
|
|
|
class VmIPItem(QTableWidgetItem):
|
|
def __init__(self, vm):
|
|
super(VmIPItem, self).__init__()
|
|
self.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled)
|
|
|
|
self.vm = vm
|
|
self.ip = self.vm.ip
|
|
if self.ip:
|
|
self.setText(self.ip)
|
|
else:
|
|
self.setText("n/a")
|
|
|
|
def __lt__(self, other):
|
|
if self.vm.qid == 0:
|
|
return True
|
|
elif other.vm.qid == 0:
|
|
return False
|
|
return super(VmIPItem, self).__lt__(other)
|
|
|
|
class VmIncludeInBackupsItem(QTableWidgetItem):
|
|
def __init__(self, vm):
|
|
super(VmIncludeInBackupsItem, self).__init__()
|
|
self.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled)
|
|
|
|
self.vm = vm
|
|
if self.vm.include_in_backups:
|
|
self.setText("Yes")
|
|
else:
|
|
self.setText("")
|
|
|
|
def __lt__(self, other):
|
|
if self.vm.qid == 0:
|
|
return True
|
|
elif other.vm.qid == 0:
|
|
return False
|
|
elif self.vm.include_in_backups == other.vm.include_in_backups:
|
|
return self.vm.qid < other.vm.qid
|
|
else:
|
|
return self.vm.include_in_backups < other.vm.include_in_backups
|
|
|
|
class VmLastBackupItem(QTableWidgetItem):
|
|
def __init__(self, vm):
|
|
super(VmLastBackupItem, self).__init__()
|
|
self.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled)
|
|
|
|
self.vm = vm
|
|
if self.vm.backup_timestamp:
|
|
self.setText(str(self.vm.backup_timestamp.date()))
|
|
else:
|
|
self.setText("")
|
|
|
|
def __lt__(self, other):
|
|
if self.vm.qid == 0:
|
|
return True
|
|
elif other.vm.qid == 0:
|
|
return False
|
|
elif self.vm.backup_timestamp == other.vm.backup_timestamp:
|
|
return self.vm.qid < other.vm.qid
|
|
elif not self.vm.backup_timestamp:
|
|
return False
|
|
elif not other.vm.backup_timestamp:
|
|
return True
|
|
else:
|
|
return self.vm.backup_timestamp < other.vm.backup_timestamp
|