Merge remote-tracking branch 'qubesos/pr/91'
* qubesos/pr/91: (27 commits) Fix long line warning Pretty confusion with regex trying to make travis happy Added exceptions for domain add and remove Fix pylint and travis errors Fix misspelling on Updates Timer() and better timeout Added missing updates() method for some widget Fix missing template updates-available Added startup progress dialog More elegant fix for settings size Removed debug print Outdated state cleanup Revert "Removed progress wait when updating template" This tries to fix some rare case when it stops receieving dbus events Added Timer for template updates Refresh table selection when pause/resume Added calls to table_selection_changed() VmRowInTable dbus events moved to VmManagerWindow Set settings dialog to minimun size, it gets adjusted properly to good view - Removed unnedeed calls to vms_in_table[vm.qid].update() - Removed update_single_row() and add direct calls to update() (Some of them could be deleted since dbus events will handle them) ...
This commit is contained in:
commit
5b752fc55b
@ -29,6 +29,9 @@ import subprocess
|
|||||||
import time
|
import time
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import traceback
|
import traceback
|
||||||
|
import threading
|
||||||
|
|
||||||
|
from pydbus import SessionBus
|
||||||
|
|
||||||
from qubesadmin import Qubes
|
from qubesadmin import Qubes
|
||||||
from qubesadmin import exc
|
from qubesadmin import exc
|
||||||
@ -36,6 +39,8 @@ from qubesadmin import exc
|
|||||||
from PyQt4 import QtGui # pylint: disable=import-error
|
from PyQt4 import QtGui # pylint: disable=import-error
|
||||||
from PyQt4 import QtCore # pylint: disable=import-error
|
from PyQt4 import QtCore # pylint: disable=import-error
|
||||||
|
|
||||||
|
from qubesmanager.about import AboutDialog
|
||||||
|
|
||||||
from . import ui_qubemanager # pylint: disable=no-name-in-module
|
from . import ui_qubemanager # pylint: disable=no-name-in-module
|
||||||
from . import thread_monitor
|
from . import thread_monitor
|
||||||
from . import table_widgets
|
from . import table_widgets
|
||||||
@ -44,9 +49,6 @@ from . import global_settings
|
|||||||
from . import restore
|
from . import restore
|
||||||
from . import backup
|
from . import backup
|
||||||
from . import log_dialog
|
from . import log_dialog
|
||||||
import threading
|
|
||||||
|
|
||||||
from qubesmanager.about import AboutDialog
|
|
||||||
|
|
||||||
|
|
||||||
class SearchBox(QtGui.QLineEdit):
|
class SearchBox(QtGui.QLineEdit):
|
||||||
@ -68,13 +70,12 @@ class SearchBox(QtGui.QLineEdit):
|
|||||||
|
|
||||||
class VmRowInTable(object):
|
class VmRowInTable(object):
|
||||||
# pylint: disable=too-few-public-methods
|
# pylint: disable=too-few-public-methods
|
||||||
|
|
||||||
def __init__(self, vm, row_no, table):
|
def __init__(self, vm, row_no, table):
|
||||||
self.vm = vm
|
self.vm = vm
|
||||||
self.row_no = row_no
|
|
||||||
# TODO: replace a various different widgets with a more generic
|
# TODO: replace a various different widgets with a more generic
|
||||||
# VmFeatureWidget or VMPropertyWidget
|
# VmFeatureWidget or VMPropertyWidget
|
||||||
|
|
||||||
|
|
||||||
table_widgets.row_height = VmManagerWindow.row_height
|
table_widgets.row_height = VmManagerWindow.row_height
|
||||||
table.setRowHeight(row_no, VmManagerWindow.row_height)
|
table.setRowHeight(row_no, VmManagerWindow.row_height)
|
||||||
|
|
||||||
@ -129,6 +130,8 @@ class VmRowInTable(object):
|
|||||||
table.setItem(row_no, VmManagerWindow.columns_indices[
|
table.setItem(row_no, VmManagerWindow.columns_indices[
|
||||||
'Last backup'], self.last_backup_widget)
|
'Last backup'], self.last_backup_widget)
|
||||||
|
|
||||||
|
self.table = table
|
||||||
|
|
||||||
def update(self, update_size_on_disk=False):
|
def update(self, update_size_on_disk=False):
|
||||||
"""
|
"""
|
||||||
Update info in a single VM row
|
Update info in a single VM row
|
||||||
@ -136,7 +139,13 @@ class VmRowInTable(object):
|
|||||||
widget will extract the data from VM object
|
widget will extract the data from VM object
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
self.info_widget.update_vm_state(self.vm)
|
self.info_widget.update_vm_state()
|
||||||
|
self.template_widget.update()
|
||||||
|
self.netvm_widget.update()
|
||||||
|
self.internal_widget.update()
|
||||||
|
self.ip_widget.update()
|
||||||
|
self.include_in_backups_widget.update()
|
||||||
|
self.last_backup_widget.update()
|
||||||
if update_size_on_disk:
|
if update_size_on_disk:
|
||||||
self.size_widget.update()
|
self.size_widget.update()
|
||||||
|
|
||||||
@ -363,16 +372,121 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QtGui.QMainWindow):
|
|||||||
|
|
||||||
self.load_manager_settings()
|
self.load_manager_settings()
|
||||||
|
|
||||||
# disabling the table for the duration of filling speeds up the process
|
|
||||||
# immensely. Yes, really.
|
|
||||||
|
|
||||||
self.table.setDisabled(True)
|
|
||||||
self.fill_table()
|
self.fill_table()
|
||||||
self.table.setEnabled(True)
|
|
||||||
|
|
||||||
self.update_size_on_disk = False
|
self.update_size_on_disk = False
|
||||||
self.shutdown_monitor = {}
|
self.shutdown_monitor = {}
|
||||||
|
|
||||||
|
# Connect dbus events
|
||||||
|
self.bus = SessionBus()
|
||||||
|
manager = self.bus.get("org.qubes.DomainManager1")
|
||||||
|
manager.DomainAdded.connect(self.on_domain_added)
|
||||||
|
manager.DomainRemoved.connect(self.on_domain_removed)
|
||||||
|
manager.Failed.connect(self.on_failed)
|
||||||
|
manager.Halted.connect(self.on_halted)
|
||||||
|
manager.Halting.connect(self.on_halting)
|
||||||
|
manager.Starting.connect(self.on_starting)
|
||||||
|
manager.Started.connect(self.on_started)
|
||||||
|
|
||||||
|
# Check Updates Timer
|
||||||
|
timer = QtCore.QTimer(self)
|
||||||
|
timer.timeout.connect(self.check_updates)
|
||||||
|
timer.start(1000 * 30) # 30s
|
||||||
|
|
||||||
|
def check_updates(self):
|
||||||
|
for vm in self.qubes_app.domains:
|
||||||
|
if vm.klass == 'TemplateVM':
|
||||||
|
self.vms_in_table[vm.qid].update()
|
||||||
|
|
||||||
|
def on_domain_added(self, _, domain):
|
||||||
|
#needs to clear cache
|
||||||
|
self.qubes_app.domains.clear_cache()
|
||||||
|
qid = int(domain.split('/')[-1])
|
||||||
|
|
||||||
|
self.table.setSortingEnabled(False)
|
||||||
|
|
||||||
|
row_no = self.table.rowCount()
|
||||||
|
self.table.setRowCount(row_no + 1)
|
||||||
|
|
||||||
|
|
||||||
|
for vm in self.qubes_app.domains:
|
||||||
|
if vm.qid == qid:
|
||||||
|
vm_row = VmRowInTable(vm, row_no, self.table)
|
||||||
|
self.vms_in_table[vm.qid] = vm_row
|
||||||
|
self.table.setSortingEnabled(True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Never should reach here
|
||||||
|
raise RuntimeError('Added domain not found')
|
||||||
|
|
||||||
|
def on_domain_removed(self, _, domain):
|
||||||
|
#needs to clear cache
|
||||||
|
self.qubes_app.domains.clear_cache()
|
||||||
|
qid = int(domain.split('/')[-1])
|
||||||
|
|
||||||
|
# Find row and remove
|
||||||
|
try:
|
||||||
|
row_index = 0
|
||||||
|
vm_item = self.table.item(row_index, self.columns_indices["Name"])
|
||||||
|
while vm_item.qid != qid:
|
||||||
|
row_index += 1
|
||||||
|
vm_item = self.table.item(row_index,\
|
||||||
|
self.columns_indices["Name"])
|
||||||
|
except:
|
||||||
|
raise RuntimeError('Deleted domain not found')
|
||||||
|
|
||||||
|
self.table.removeRow(row_index)
|
||||||
|
del self.vms_in_table[qid]
|
||||||
|
|
||||||
|
def on_failed(self, _, domain):
|
||||||
|
qid = int(domain.split('/')[-1])
|
||||||
|
self.vms_in_table[qid].update()
|
||||||
|
|
||||||
|
if self.vms_in_table[qid].vm == self.get_selected_vm():
|
||||||
|
self.table_selection_changed()
|
||||||
|
|
||||||
|
def on_halted(self, _, domain):
|
||||||
|
qid = int(domain.split('/')[-1])
|
||||||
|
self.vms_in_table[qid].update()
|
||||||
|
|
||||||
|
if self.vms_in_table[qid].vm == self.get_selected_vm():
|
||||||
|
self.table_selection_changed()
|
||||||
|
|
||||||
|
# Check if is TemplatVM and update related AppVMs
|
||||||
|
starting_vm = self.vms_in_table[qid]
|
||||||
|
if starting_vm.vm.klass == 'TemplateVM':
|
||||||
|
for vm in starting_vm.vm.appvms:
|
||||||
|
if vm.klass == 'AppVM':
|
||||||
|
self.vms_in_table[vm.qid].update()
|
||||||
|
|
||||||
|
def on_halting(self, _, domain):
|
||||||
|
qid = int(domain.split('/')[-1])
|
||||||
|
self.vms_in_table[qid].update()
|
||||||
|
|
||||||
|
if self.vms_in_table[qid].vm == self.get_selected_vm():
|
||||||
|
self.table_selection_changed()
|
||||||
|
|
||||||
|
def on_started(self, _, domain):
|
||||||
|
qid = int(domain.split('/')[-1])
|
||||||
|
self.vms_in_table[qid].update()
|
||||||
|
|
||||||
|
if self.vms_in_table[qid].vm == self.get_selected_vm():
|
||||||
|
self.table_selection_changed()
|
||||||
|
|
||||||
|
def on_starting(self, _, domain):
|
||||||
|
qid = int(domain.split('/')[-1])
|
||||||
|
self.vms_in_table[qid].update()
|
||||||
|
|
||||||
|
if self.vms_in_table[qid].vm == self.get_selected_vm():
|
||||||
|
self.table_selection_changed()
|
||||||
|
|
||||||
|
# Check if is TemplatVM and update related AppVMs
|
||||||
|
starting_vm = self.vms_in_table[qid]
|
||||||
|
if starting_vm.vm.klass == 'TemplateVM':
|
||||||
|
for vm in starting_vm.vm.appvms:
|
||||||
|
if vm.klass == 'AppVM':
|
||||||
|
self.vms_in_table[vm.qid].update()
|
||||||
|
|
||||||
def load_manager_settings(self):
|
def load_manager_settings(self):
|
||||||
# visible columns
|
# visible columns
|
||||||
self.visible_columns_count = 0
|
self.visible_columns_count = 0
|
||||||
@ -403,26 +517,16 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QtGui.QMainWindow):
|
|||||||
def get_vms_list(self):
|
def get_vms_list(self):
|
||||||
return [vm for vm in self.qubes_app.domains]
|
return [vm for vm in self.qubes_app.domains]
|
||||||
|
|
||||||
def update_single_row(self, vm):
|
|
||||||
# this fuction should be used to update a row that already exists
|
|
||||||
# to add a row, one needs to use the update_table function - the
|
|
||||||
# whole table needs to be redrawn (and sorted)
|
|
||||||
if vm in self.qubes_app.domains:
|
|
||||||
self.vms_in_table[vm.qid].update()
|
|
||||||
else:
|
|
||||||
self.update_table()
|
|
||||||
|
|
||||||
def fill_table(self):
|
def fill_table(self):
|
||||||
# save current selection
|
progress = QtGui.QProgressDialog(
|
||||||
row_index = self.table.currentRow()
|
self.tr(
|
||||||
selected_qid = -1
|
"Loading Qube Manager..."), "", 0, 0)
|
||||||
if row_index != -1:
|
progress.setWindowTitle(self.tr("Qube Manager"))
|
||||||
vm_item = self.table.item(row_index, self.columns_indices["Name"])
|
progress.setCancelButton(None)
|
||||||
if vm_item:
|
progress.setModal(True)
|
||||||
selected_qid = vm_item.qid
|
progress.show()
|
||||||
|
|
||||||
self.table.setSortingEnabled(False)
|
self.table.setSortingEnabled(False)
|
||||||
self.table.clearContents()
|
|
||||||
vms_list = self.get_vms_list()
|
vms_list = self.get_vms_list()
|
||||||
|
|
||||||
vms_in_table = {}
|
vms_in_table = {}
|
||||||
@ -439,12 +543,9 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QtGui.QMainWindow):
|
|||||||
|
|
||||||
self.vms_list = vms_list
|
self.vms_list = vms_list
|
||||||
self.vms_in_table = vms_in_table
|
self.vms_in_table = vms_in_table
|
||||||
if selected_qid in vms_in_table.keys():
|
|
||||||
self.table.setCurrentItem(
|
|
||||||
self.vms_in_table[selected_qid].name_widget)
|
|
||||||
self.table.setSortingEnabled(True)
|
self.table.setSortingEnabled(True)
|
||||||
|
|
||||||
self.showhide_vms()
|
progress.hide()
|
||||||
|
|
||||||
def showhide_vms(self):
|
def showhide_vms(self):
|
||||||
if not self.search:
|
if not self.search:
|
||||||
@ -467,19 +568,6 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QtGui.QMainWindow):
|
|||||||
def action_search_triggered(self):
|
def action_search_triggered(self):
|
||||||
self.searchbox.setFocus()
|
self.searchbox.setFocus()
|
||||||
|
|
||||||
def update_table(self):
|
|
||||||
# disabling the table speeds up the process of filling it
|
|
||||||
self.table.setDisabled(True)
|
|
||||||
self.fill_table()
|
|
||||||
self.table.setEnabled(True)
|
|
||||||
# TODO: instead of manually refreshing the entire table, use dbus events
|
|
||||||
|
|
||||||
# reapply sorting
|
|
||||||
if self.sort_by_column:
|
|
||||||
self.table.sortByColumn(self.columns_indices[self.sort_by_column])
|
|
||||||
|
|
||||||
self.table_selection_changed()
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
# noinspection PyPep8Naming
|
||||||
def sort_indicator_changed(self, column, order):
|
def sort_indicator_changed(self, column, order):
|
||||||
self.sort_by_column = [name for name in self.columns_indices if
|
self.sort_by_column = [name for name in self.columns_indices if
|
||||||
@ -530,8 +618,6 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QtGui.QMainWindow):
|
|||||||
self.action_set_keyboard_layout.setEnabled(
|
self.action_set_keyboard_layout.setEnabled(
|
||||||
vm.qid != 0 and
|
vm.qid != 0 and
|
||||||
vm.get_power_state() != "Paused" and vm.is_running())
|
vm.get_power_state() != "Paused" and vm.is_running())
|
||||||
|
|
||||||
self.update_single_row(vm)
|
|
||||||
else:
|
else:
|
||||||
self.action_settings.setEnabled(False)
|
self.action_settings.setEnabled(False)
|
||||||
self.action_removevm.setEnabled(False)
|
self.action_removevm.setEnabled(False)
|
||||||
@ -640,7 +726,6 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QtGui.QMainWindow):
|
|||||||
self.tr("ERROR: {0}").format(
|
self.tr("ERROR: {0}").format(
|
||||||
t_monitor.error_msg))
|
t_monitor.error_msg))
|
||||||
|
|
||||||
self.update_table()
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def do_remove_vm(vm, qubes_app, t_monitor):
|
def do_remove_vm(vm, qubes_app, t_monitor):
|
||||||
@ -695,7 +780,6 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QtGui.QMainWindow):
|
|||||||
self.tr("Exception while cloning:<br>{0}").format(
|
self.tr("Exception while cloning:<br>{0}").format(
|
||||||
t_monitor.error_msg))
|
t_monitor.error_msg))
|
||||||
|
|
||||||
self.update_table()
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def do_clone_vm(src_vm, qubes_app, dst_name, t_monitor):
|
def do_clone_vm(src_vm, qubes_app, dst_name, t_monitor):
|
||||||
@ -716,6 +800,8 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QtGui.QMainWindow):
|
|||||||
if vm.get_power_state() in ["Paused", "Suspended"]:
|
if vm.get_power_state() in ["Paused", "Suspended"]:
|
||||||
try:
|
try:
|
||||||
vm.unpause()
|
vm.unpause()
|
||||||
|
self.vms_in_table[vm.qid].update()
|
||||||
|
self.table_selection_changed()
|
||||||
except exc.QubesException as ex:
|
except exc.QubesException as ex:
|
||||||
QtGui.QMessageBox.warning(
|
QtGui.QMessageBox.warning(
|
||||||
None, self.tr("Error unpausing Qube!"),
|
None, self.tr("Error unpausing Qube!"),
|
||||||
@ -723,7 +809,6 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QtGui.QMainWindow):
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.start_vm(vm)
|
self.start_vm(vm)
|
||||||
self.update_single_row(vm)
|
|
||||||
|
|
||||||
def start_vm(self, vm):
|
def start_vm(self, vm):
|
||||||
if vm.is_running():
|
if vm.is_running():
|
||||||
@ -744,7 +829,6 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QtGui.QMainWindow):
|
|||||||
self.tr("Error starting Qube!"),
|
self.tr("Error starting Qube!"),
|
||||||
self.tr("ERROR: {0}").format(t_monitor.error_msg))
|
self.tr("ERROR: {0}").format(t_monitor.error_msg))
|
||||||
|
|
||||||
self.update_single_row(vm)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def do_start_vm(vm, t_monitor):
|
def do_start_vm(vm, t_monitor):
|
||||||
@ -769,7 +853,8 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QtGui.QMainWindow):
|
|||||||
vm = self.get_selected_vm()
|
vm = self.get_selected_vm()
|
||||||
try:
|
try:
|
||||||
vm.pause()
|
vm.pause()
|
||||||
self.update_single_row(vm)
|
self.vms_in_table[vm.qid].update()
|
||||||
|
self.table_selection_changed()
|
||||||
except exc.QubesException as ex:
|
except exc.QubesException as ex:
|
||||||
QtGui.QMessageBox.warning(
|
QtGui.QMessageBox.warning(
|
||||||
None,
|
None,
|
||||||
@ -794,7 +879,6 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QtGui.QMainWindow):
|
|||||||
if reply == QtGui.QMessageBox.Yes:
|
if reply == QtGui.QMessageBox.Yes:
|
||||||
self.shutdown_vm(vm)
|
self.shutdown_vm(vm)
|
||||||
|
|
||||||
self.update_single_row(vm)
|
|
||||||
|
|
||||||
def shutdown_vm(self, vm, shutdown_time=vm_shutdown_timeout,
|
def shutdown_vm(self, vm, shutdown_time=vm_shutdown_timeout,
|
||||||
check_time=vm_restart_check_timeout, and_restart=False):
|
check_time=vm_restart_check_timeout, and_restart=False):
|
||||||
@ -835,8 +919,6 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QtGui.QMainWindow):
|
|||||||
else:
|
else:
|
||||||
self.start_vm(vm)
|
self.start_vm(vm)
|
||||||
|
|
||||||
self.update_single_row(vm)
|
|
||||||
|
|
||||||
# noinspection PyArgumentList
|
# noinspection PyArgumentList
|
||||||
@QtCore.pyqtSlot(name='on_action_killvm_triggered')
|
@QtCore.pyqtSlot(name='on_action_killvm_triggered')
|
||||||
def action_killvm_triggered(self):
|
def action_killvm_triggered(self):
|
||||||
@ -879,7 +961,7 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QtGui.QMainWindow):
|
|||||||
settings_window = settings.VMSettingsWindow(
|
settings_window = settings.VMSettingsWindow(
|
||||||
vm, self.qt_app, "basic")
|
vm, self.qt_app, "basic")
|
||||||
settings_window.exec_()
|
settings_window.exec_()
|
||||||
self.update_single_row(vm)
|
self.vms_in_table[vm.qid].update()
|
||||||
|
|
||||||
# noinspection PyArgumentList
|
# noinspection PyArgumentList
|
||||||
@QtCore.pyqtSlot(name='on_action_appmenus_triggered')
|
@QtCore.pyqtSlot(name='on_action_appmenus_triggered')
|
||||||
@ -890,11 +972,6 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QtGui.QMainWindow):
|
|||||||
vm, self.qt_app, "applications")
|
vm, self.qt_app, "applications")
|
||||||
settings_window.exec_()
|
settings_window.exec_()
|
||||||
|
|
||||||
# noinspection PyArgumentList
|
|
||||||
@QtCore.pyqtSlot(name='on_action_refresh_list_triggered')
|
|
||||||
def action_refresh_list_triggered(self):
|
|
||||||
self.qubes_app.domains.clear_cache()
|
|
||||||
self.update_table()
|
|
||||||
|
|
||||||
# noinspection PyArgumentList
|
# noinspection PyArgumentList
|
||||||
@QtCore.pyqtSlot(name='on_action_updatevm_triggered')
|
@QtCore.pyqtSlot(name='on_action_updatevm_triggered')
|
||||||
@ -940,7 +1017,6 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QtGui.QMainWindow):
|
|||||||
self.tr("Error on Qube update!"),
|
self.tr("Error on Qube update!"),
|
||||||
self.tr("ERROR: {0}").format(t_monitor.error_msg))
|
self.tr("ERROR: {0}").format(t_monitor.error_msg))
|
||||||
|
|
||||||
self.update_single_row(vm)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def do_update_vm(vm, t_monitor):
|
def do_update_vm(vm, t_monitor):
|
||||||
@ -1213,10 +1289,7 @@ def main():
|
|||||||
qubes_app = Qubes()
|
qubes_app = Qubes()
|
||||||
|
|
||||||
manager_window = VmManagerWindow(qt_app, qubes_app)
|
manager_window = VmManagerWindow(qt_app, qubes_app)
|
||||||
|
|
||||||
manager_window.show()
|
manager_window.show()
|
||||||
timer = QtCore.QTimer()
|
|
||||||
timer.singleShot(1, manager_window.update_table)
|
|
||||||
qt_app.exec_()
|
qt_app.exec_()
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,10 +18,10 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Lesser General Public License along
|
# You should have received a copy of the GNU Lesser General Public License along
|
||||||
# with this program; if not, see <http://www.gnu.org/licenses/>.
|
# with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
import datetime
|
||||||
|
|
||||||
from PyQt4 import QtGui # pylint: disable=import-error
|
from PyQt4 import QtGui # pylint: disable=import-error
|
||||||
from PyQt4 import QtCore # pylint: disable=import-error
|
from PyQt4 import QtCore # pylint: disable=import-error
|
||||||
import datetime
|
|
||||||
# pylint: disable=too-few-public-methods
|
# pylint: disable=too-few-public-methods
|
||||||
|
|
||||||
power_order = QtCore.Qt.DescendingOrder
|
power_order = QtCore.Qt.DescendingOrder
|
||||||
@ -110,7 +110,6 @@ class VmTypeWidget(VmIconWidget):
|
|||||||
|
|
||||||
|
|
||||||
class VmLabelWidget(VmIconWidget):
|
class VmLabelWidget(VmIconWidget):
|
||||||
|
|
||||||
class VmLabelItem(QtGui.QTableWidgetItem):
|
class VmLabelItem(QtGui.QTableWidgetItem):
|
||||||
def __init__(self, value, vm):
|
def __init__(self, value, vm):
|
||||||
super(VmLabelWidget.VmLabelItem, self).__init__()
|
super(VmLabelWidget.VmLabelItem, self).__init__()
|
||||||
@ -254,9 +253,9 @@ class VmInfoWidget(QtGui.QWidget):
|
|||||||
|
|
||||||
self.table_item = self.VmInfoItem(self.upd_info.table_item, vm)
|
self.table_item = self.VmInfoItem(self.upd_info.table_item, vm)
|
||||||
|
|
||||||
def update_vm_state(self, vm):
|
def update_vm_state(self):
|
||||||
self.on_icon.update()
|
self.on_icon.update()
|
||||||
self.upd_info.update_outdated(vm)
|
self.upd_info.update_outdated()
|
||||||
|
|
||||||
|
|
||||||
class VmTemplateItem(QtGui.QTableWidgetItem):
|
class VmTemplateItem(QtGui.QTableWidgetItem):
|
||||||
@ -264,18 +263,19 @@ class VmTemplateItem(QtGui.QTableWidgetItem):
|
|||||||
super(VmTemplateItem, self).__init__()
|
super(VmTemplateItem, self).__init__()
|
||||||
self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
||||||
self.vm = vm
|
self.vm = vm
|
||||||
|
self.setTextAlignment(QtCore.Qt.AlignVCenter)
|
||||||
|
self.update()
|
||||||
|
|
||||||
if getattr(vm, 'template', None) is not None:
|
def update(self):
|
||||||
self.setText(vm.template.name)
|
if getattr(self.vm, 'template', None) is not None:
|
||||||
|
self.setText(self.vm.template.name)
|
||||||
else:
|
else:
|
||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
font.setStyle(QtGui.QFont.StyleItalic)
|
font.setStyle(QtGui.QFont.StyleItalic)
|
||||||
self.setFont(font)
|
self.setFont(font)
|
||||||
self.setTextColor(QtGui.QColor("gray"))
|
self.setTextColor(QtGui.QColor("gray"))
|
||||||
|
|
||||||
self.setText(vm.klass)
|
self.setText(self.vm.klass)
|
||||||
|
|
||||||
self.setTextAlignment(QtCore.Qt.AlignVCenter)
|
|
||||||
|
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
if self.vm.qid == 0:
|
if self.vm.qid == 0:
|
||||||
@ -292,13 +292,14 @@ class VmNetvmItem(QtGui.QTableWidgetItem):
|
|||||||
super(VmNetvmItem, self).__init__()
|
super(VmNetvmItem, self).__init__()
|
||||||
self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
||||||
self.vm = vm
|
self.vm = vm
|
||||||
|
self.setTextAlignment(QtCore.Qt.AlignVCenter)
|
||||||
|
self.update()
|
||||||
|
|
||||||
if getattr(vm, 'netvm', None) is None:
|
def update(self):
|
||||||
|
if getattr(self.vm, 'netvm', None) is None:
|
||||||
self.setText("n/a")
|
self.setText("n/a")
|
||||||
else:
|
else:
|
||||||
self.setText(vm.netvm.name)
|
self.setText(self.vm.netvm.name)
|
||||||
|
|
||||||
self.setTextAlignment(QtCore.Qt.AlignVCenter)
|
|
||||||
|
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
if self.vm.qid == 0:
|
if self.vm.qid == 0:
|
||||||
@ -316,10 +317,13 @@ class VmInternalItem(QtGui.QTableWidgetItem):
|
|||||||
self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
||||||
|
|
||||||
self.vm = vm
|
self.vm = vm
|
||||||
self.internal = vm.features.get('internal', False)
|
self.update()
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
self.internal = self.vm.features.get('internal', False)
|
||||||
self.setText("Yes" if self.internal else "")
|
self.setText("Yes" if self.internal else "")
|
||||||
|
|
||||||
|
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
if self.vm.qid == 0:
|
if self.vm.qid == 0:
|
||||||
return True
|
return True
|
||||||
@ -330,7 +334,6 @@ class VmInternalItem(QtGui.QTableWidgetItem):
|
|||||||
|
|
||||||
# features man qvm-features
|
# features man qvm-features
|
||||||
class VmUpdateInfoWidget(QtGui.QWidget):
|
class VmUpdateInfoWidget(QtGui.QWidget):
|
||||||
|
|
||||||
class VmUpdateInfoItem(QtGui.QTableWidgetItem):
|
class VmUpdateInfoItem(QtGui.QTableWidgetItem):
|
||||||
def __init__(self, value, vm):
|
def __init__(self, value, vm):
|
||||||
super(VmUpdateInfoWidget.VmUpdateInfoItem, self).__init__()
|
super(VmUpdateInfoWidget.VmUpdateInfoItem, self).__init__()
|
||||||
@ -367,34 +370,38 @@ class VmUpdateInfoWidget(QtGui.QWidget):
|
|||||||
layout.addWidget(self.icon, alignment=QtCore.Qt.AlignCenter)
|
layout.addWidget(self.icon, alignment=QtCore.Qt.AlignCenter)
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
self.vm = vm
|
||||||
|
|
||||||
self.previous_outdated_state = None
|
self.previous_outdated_state = None
|
||||||
self.previous_update_recommended = None
|
self.previous_update_recommended = None
|
||||||
self.value = None
|
self.value = None
|
||||||
self.table_item = VmUpdateInfoWidget.VmUpdateInfoItem(self.value, vm)
|
self.table_item = VmUpdateInfoWidget.VmUpdateInfoItem(self.value, vm)
|
||||||
self.update_outdated(vm)
|
self.update_outdated()
|
||||||
|
|
||||||
def update_outdated(self, vm):
|
|
||||||
|
|
||||||
|
def update_outdated(self):
|
||||||
outdated_state = False
|
outdated_state = False
|
||||||
|
|
||||||
for vol in vm.volumes.values():
|
if self.vm.is_running():
|
||||||
if vol.is_outdated():
|
if hasattr(self.vm, 'template') and self.vm.template.is_running():
|
||||||
outdated_state = "outdated"
|
outdated_state = "to-be-outdated"
|
||||||
break
|
|
||||||
|
|
||||||
if not outdated_state and getattr(vm, 'template', None)\
|
if not outdated_state:
|
||||||
and vm.template.is_running():
|
for vol in self.vm.volumes.values():
|
||||||
outdated_state = "to-be-outdated"
|
if vol.is_outdated():
|
||||||
if outdated_state != self.previous_outdated_state:
|
outdated_state = "outdated"
|
||||||
self.update_status_widget(outdated_state)
|
break
|
||||||
self.previous_outdated_state = outdated_state
|
|
||||||
|
|
||||||
updates_available = vm.features.get('updates-available', False)
|
elif self.vm.klass == 'TemplateVM' and \
|
||||||
if updates_available != self.previous_update_recommended:
|
self.vm.features.get('updates-available', False):
|
||||||
self.update_status_widget("update" if updates_available else None)
|
outdated_state = 'update'
|
||||||
self.previous_update_recommended = updates_available
|
|
||||||
|
self.update_status_widget(outdated_state)
|
||||||
|
|
||||||
def update_status_widget(self, state):
|
def update_status_widget(self, state):
|
||||||
|
if state == self.previous_outdated_state:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.previous_outdated_state = state
|
||||||
self.value = state
|
self.value = state
|
||||||
self.table_item.set_value(state)
|
self.table_item.set_value(state)
|
||||||
if state == "update":
|
if state == "update":
|
||||||
@ -414,22 +421,22 @@ class VmUpdateInfoWidget(QtGui.QWidget):
|
|||||||
"The Template must be stopped before changes from its "
|
"The Template must be stopped before changes from its "
|
||||||
"current session can be picked up by this qube.")
|
"current session can be picked up by this qube.")
|
||||||
else:
|
else:
|
||||||
label_text = ""
|
|
||||||
icon_path = None
|
icon_path = None
|
||||||
tooltip_text = None
|
|
||||||
|
if hasattr(self, 'icon'):
|
||||||
|
self.icon.setVisible(False)
|
||||||
|
self.layout().removeWidget(self.icon)
|
||||||
|
del self.icon
|
||||||
|
|
||||||
if self.show_text:
|
if self.show_text:
|
||||||
self.label.setText(label_text)
|
self.label.setText(label_text)
|
||||||
else:
|
else:
|
||||||
self.layout().removeWidget(self.icon)
|
|
||||||
self.icon.deleteLater()
|
|
||||||
if icon_path is not None:
|
if icon_path is not None:
|
||||||
self.icon = VmIconWidget(icon_path, True, 0.7)
|
self.icon = VmIconWidget(icon_path, True, 0.7)
|
||||||
self.icon.setToolTip(tooltip_text)
|
self.icon.setToolTip(tooltip_text)
|
||||||
else:
|
self.layout().addWidget(self.icon,\
|
||||||
self.icon = QtGui.QLabel(label_text)
|
alignment=QtCore.Qt.AlignCenter)
|
||||||
self.layout().addWidget(self.icon, alignment=QtCore.Qt.AlignCenter)
|
self.icon.setVisible(True)
|
||||||
|
|
||||||
|
|
||||||
class VmSizeOnDiskItem(QtGui.QTableWidgetItem):
|
class VmSizeOnDiskItem(QtGui.QTableWidgetItem):
|
||||||
def __init__(self, vm):
|
def __init__(self, vm):
|
||||||
@ -465,6 +472,9 @@ class VmIPItem(QtGui.QTableWidgetItem):
|
|||||||
self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
||||||
|
|
||||||
self.vm = vm
|
self.vm = vm
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def update(self):
|
||||||
self.ip = getattr(self.vm, 'ip', None)
|
self.ip = getattr(self.vm, 'ip', None)
|
||||||
self.setText(self.ip if self.ip is not None else 'n/a')
|
self.setText(self.ip if self.ip is not None else 'n/a')
|
||||||
|
|
||||||
@ -482,6 +492,9 @@ class VmIncludeInBackupsItem(QtGui.QTableWidgetItem):
|
|||||||
self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
||||||
|
|
||||||
self.vm = vm
|
self.vm = vm
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def update(self):
|
||||||
if getattr(self.vm, 'include_in_backups', None):
|
if getattr(self.vm, 'include_in_backups', None):
|
||||||
self.setText("Yes")
|
self.setText("Yes")
|
||||||
else:
|
else:
|
||||||
@ -503,6 +516,9 @@ class VmLastBackupItem(QtGui.QTableWidgetItem):
|
|||||||
self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
||||||
|
|
||||||
self.vm = vm
|
self.vm = vm
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def update(self):
|
||||||
self.backup_timestamp = getattr(self.vm, 'backup_timestamp', None)
|
self.backup_timestamp = getattr(self.vm, 'backup_timestamp', None)
|
||||||
|
|
||||||
if self.backup_timestamp:
|
if self.backup_timestamp:
|
||||||
|
@ -281,7 +281,6 @@
|
|||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="action_search"/>
|
<addaction name="action_search"/>
|
||||||
<addaction name="action_refresh_list"/>
|
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menu_vm">
|
<widget class="QMenu" name="menu_vm">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@ -369,7 +368,6 @@
|
|||||||
<addaction name="action_backup"/>
|
<addaction name="action_backup"/>
|
||||||
<addaction name="action_restore"/>
|
<addaction name="action_restore"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="action_refresh_list"/>
|
|
||||||
</widget>
|
</widget>
|
||||||
<action name="action_createvm">
|
<action name="action_createvm">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
@ -818,18 +816,6 @@
|
|||||||
<string>Ctrl+F</string>
|
<string>Ctrl+F</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="action_refresh_list">
|
|
||||||
<property name="icon">
|
|
||||||
<iconset resource="../resources.qrc">
|
|
||||||
<normaloff>:/outdated.png</normaloff>:/outdated.png</iconset>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Refresh qube list</string>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Refresh qube list</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="action_exit">
|
<action name="action_exit">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Exit Qube Manager</string>
|
<string>&Exit Qube Manager</string>
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1587</width>
|
<width>680</width>
|
||||||
<height>861</height>
|
<height>656</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
Loading…
Reference in New Issue
Block a user