Merge branch 'master' of https://github.com/QubesOS/qubes-manager into template_menu
# Conflicts: # qubesmanager/qube_manager.py
This commit is contained in:
commit
f90ab86a73
14
.gitlab-ci.yml
Normal file
14
.gitlab-ci.yml
Normal file
@ -0,0 +1,14 @@
|
||||
include:
|
||||
- project: 'QubesOS/qubes-continuous-integration'
|
||||
file: '/r4.1/gitlab-base.yml'
|
||||
- project: 'QubesOS/qubes-continuous-integration'
|
||||
file: '/r4.1/gitlab-dom0.yml'
|
||||
- project: 'QubesOS/qubes-continuous-integration'
|
||||
file: '/r4.1/gitlab-vm.yml'
|
||||
|
||||
checks:pylint:
|
||||
stage: checks
|
||||
before_script:
|
||||
- pip3 install --quiet -r ci/requirements.txt
|
||||
script:
|
||||
- PYTHONPATH="test-packages:$PYTHONPATH" python3 -m pylint qubesmanager
|
2
debian/control
vendored
2
debian/control
vendored
@ -7,7 +7,7 @@ Build-Depends:
|
||||
dh-python,
|
||||
python3-all,
|
||||
python3-setuptools,
|
||||
qt5-default,
|
||||
qtbase5-dev,
|
||||
qttools5-dev-tools,
|
||||
pyqt5-dev-tools
|
||||
Standards-Version: 4.3.0
|
||||
|
1
debian/rules
vendored
1
debian/rules
vendored
@ -2,6 +2,7 @@
|
||||
|
||||
include /usr/share/dpkg/default.mk
|
||||
export DESTDIR=$(shell pwd)/debian/tmp
|
||||
export QT_SELECT=qt5
|
||||
|
||||
%:
|
||||
dh $@ --with python3 --buildsystem=pybuild
|
||||
|
@ -37,7 +37,7 @@ from PyQt5.QtCore import (Qt, QAbstractTableModel, QObject, pyqtSlot, QEvent,
|
||||
# pylint: disable=import-error
|
||||
from PyQt5.QtWidgets import (QLineEdit, QStyledItemDelegate, QToolTip,
|
||||
QMenu, QInputDialog, QMainWindow, QProgressDialog, QStyleOptionViewItem,
|
||||
QAbstractItemView, QMessageBox, QAction)
|
||||
QMessageBox)
|
||||
|
||||
# pylint: disable=import-error
|
||||
from PyQt5.QtGui import (QIcon, QPixmap, QRegExpValidator, QFont, QColor)
|
||||
@ -630,8 +630,11 @@ class RunCommandThread(common_threads.QubesThread):
|
||||
except (ChildProcessError, exc.QubesException) as ex:
|
||||
self.msg = (self.tr("Error while running command!"), str(ex))
|
||||
|
||||
|
||||
class QubesProxyModel(QSortFilterProxyModel):
|
||||
def __init__(self, window):
|
||||
super().__init__()
|
||||
self.window = window
|
||||
|
||||
def lessThan(self, left, right):
|
||||
if left.data(self.sortRole()) != right.data(self.sortRole()):
|
||||
return super().lessThan(left, right)
|
||||
@ -641,6 +644,31 @@ class QubesProxyModel(QSortFilterProxyModel):
|
||||
|
||||
return left_vm.name.lower() < right_vm.name.lower()
|
||||
|
||||
# pylint: disable=too-many-return-statements
|
||||
def filterAcceptsRow(self, sourceRow, sourceParent):
|
||||
if self.window.show_all.isChecked():
|
||||
return super().filterAcceptsRow(sourceRow, sourceParent)
|
||||
|
||||
index = self.sourceModel().index(sourceRow, 0, sourceParent)
|
||||
vm = self.sourceModel().data(index, Qt.UserRole)
|
||||
|
||||
if self.window.show_running.isChecked() and \
|
||||
vm.state['power'] == 'Running':
|
||||
return super().filterAcceptsRow(sourceRow, sourceParent)
|
||||
if self.window.show_halted.isChecked() and \
|
||||
vm.state['power'] == 'Halted':
|
||||
return super().filterAcceptsRow(sourceRow, sourceParent)
|
||||
if self.window.show_network.isChecked() and \
|
||||
getattr(vm.vm, 'provides_network', False):
|
||||
return super().filterAcceptsRow(sourceRow, sourceParent)
|
||||
if self.window.show_templates.isChecked() and vm.klass == 'TemplateVM':
|
||||
return super().filterAcceptsRow(sourceRow, sourceParent)
|
||||
if self.window.show_standalone.isChecked() \
|
||||
and vm.klass == 'StandaloneVM':
|
||||
return super().filterAcceptsRow(sourceRow, sourceParent)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow):
|
||||
# suppress saving settings while initializing widgets
|
||||
@ -659,7 +687,7 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow):
|
||||
self.searchbox.setValidator(QRegExpValidator(
|
||||
QRegExp("[a-zA-Z0-9_-]*", Qt.CaseInsensitive), None))
|
||||
self.searchbox.textChanged.connect(self.do_search)
|
||||
self.searchContainer.addWidget(self.searchbox)
|
||||
self.searchContainer.insertWidget(1, self.searchbox)
|
||||
|
||||
self.settings_windows = {}
|
||||
|
||||
@ -668,33 +696,7 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow):
|
||||
|
||||
self.init_template_menu()
|
||||
self.init_network_menu()
|
||||
self.context_menu = QMenu(self)
|
||||
|
||||
self.context_menu.addAction(self.action_settings)
|
||||
self.context_menu.addMenu(self.template_menu)
|
||||
self.context_menu.addMenu(self.network_menu)
|
||||
self.context_menu.addAction(self.action_editfwrules)
|
||||
self.context_menu.addAction(self.action_appmenus)
|
||||
self.context_menu.addAction(self.action_set_keyboard_layout)
|
||||
self.context_menu.addSeparator()
|
||||
|
||||
self.context_menu.addAction(self.action_updatevm)
|
||||
self.context_menu.addAction(self.action_run_command_in_vm)
|
||||
self.context_menu.addAction(self.action_open_console)
|
||||
self.context_menu.addAction(self.action_resumevm)
|
||||
self.context_menu.addAction(self.action_startvm_tools_install)
|
||||
self.context_menu.addAction(self.action_pausevm)
|
||||
self.context_menu.addAction(self.action_shutdownvm)
|
||||
self.context_menu.addAction(self.action_restartvm)
|
||||
self.context_menu.addAction(self.action_killvm)
|
||||
self.context_menu.addSeparator()
|
||||
|
||||
self.context_menu.addAction(self.action_clonevm)
|
||||
self.context_menu.addAction(self.action_removevm)
|
||||
self.context_menu.addSeparator()
|
||||
|
||||
self.context_menu.addMenu(self.logs_menu)
|
||||
self.context_menu.addSeparator()
|
||||
self.__init_context_menu()
|
||||
|
||||
self.tools_context_menu = QMenu(self)
|
||||
self.tools_context_menu.addAction(self.action_toolbar)
|
||||
@ -706,6 +708,7 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow):
|
||||
lambda pos: self.open_tools_context_menu(self.toolbar, pos))
|
||||
self.action_menubar.toggled.connect(self.showhide_menubar)
|
||||
self.action_toolbar.toggled.connect(self.showhide_toolbar)
|
||||
self.action_compact_view.toggled.connect(self.set_compactview)
|
||||
self.logs_menu.triggered.connect(self.show_log)
|
||||
|
||||
self.table.resizeColumnsToContents()
|
||||
@ -717,7 +720,7 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow):
|
||||
self.fill_cache()
|
||||
self.qubes_model = QubesTableModel(self.qubes_cache)
|
||||
|
||||
self.proxy = QubesProxyModel()
|
||||
self.proxy = QubesProxyModel(self)
|
||||
self.proxy.setSourceModel(self.qubes_model)
|
||||
self.proxy.setSortRole(Qt.UserRole + 1)
|
||||
self.proxy.setSortCaseSensitivity(Qt.CaseInsensitive)
|
||||
@ -727,10 +730,16 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow):
|
||||
self.proxy.layoutChanged.connect(self.update_template_menu)
|
||||
self.proxy.layoutChanged.connect(self.update_network_menu)
|
||||
|
||||
self.show_running.stateChanged.connect(self.invalidate)
|
||||
self.show_halted.stateChanged.connect(self.invalidate)
|
||||
self.show_network.stateChanged.connect(self.invalidate)
|
||||
self.show_templates.stateChanged.connect(self.invalidate)
|
||||
self.show_standalone.stateChanged.connect(self.invalidate)
|
||||
self.show_all.stateChanged.connect(self.invalidate)
|
||||
|
||||
self.table.setModel(self.proxy)
|
||||
self.table.setItemDelegateForColumn(3, StateIconDelegate())
|
||||
self.table.resizeColumnsToContents()
|
||||
self.table.setSelectionMode(QAbstractItemView.ExtendedSelection)
|
||||
selection_model = self.table.selectionModel()
|
||||
selection_model.selectionChanged.connect(self.table_selection_changed)
|
||||
|
||||
@ -747,6 +756,8 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow):
|
||||
self.menu_view.addSeparator()
|
||||
self.menu_view.addAction(self.action_toolbar)
|
||||
self.menu_view.addAction(self.action_menubar)
|
||||
self.menu_view.addSeparator()
|
||||
self.menu_view.addAction(self.action_compact_view)
|
||||
|
||||
try:
|
||||
self.load_manager_settings()
|
||||
@ -850,12 +861,54 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow):
|
||||
self.tr("Change Network Error"),
|
||||
self.tr((str(ex))))
|
||||
|
||||
def __init_context_menu(self):
|
||||
self.context_menu = QMenu(self)
|
||||
self.context_menu.addAction(self.action_settings)
|
||||
self.context_menu.addAction(self.template_menu.menuAction())
|
||||
self.context_menu.addAction(self.network_menu.menuAction())
|
||||
self.context_menu.addAction(self.action_editfwrules)
|
||||
self.context_menu.addAction(self.action_appmenus)
|
||||
self.context_menu.addAction(self.action_set_keyboard_layout)
|
||||
self.context_menu.addSeparator()
|
||||
self.context_menu.addAction(self.action_updatevm)
|
||||
self.context_menu.addAction(self.action_run_command_in_vm)
|
||||
self.context_menu.addAction(self.action_open_console)
|
||||
self.context_menu.addAction(self.action_resumevm)
|
||||
self.context_menu.addAction(self.action_startvm_tools_install)
|
||||
self.context_menu.addAction(self.action_pausevm)
|
||||
self.context_menu.addAction(self.action_shutdownvm)
|
||||
self.context_menu.addAction(self.action_restartvm)
|
||||
self.context_menu.addAction(self.action_killvm)
|
||||
self.context_menu.addSeparator()
|
||||
self.context_menu.addAction(self.action_clonevm)
|
||||
self.context_menu.addAction(self.action_removevm)
|
||||
self.context_menu.addSeparator()
|
||||
self.context_menu.addMenu(self.logs_menu)
|
||||
self.context_menu.addSeparator()
|
||||
|
||||
def save_showing(self):
|
||||
self.manager_settings.setValue('show/running',
|
||||
self.show_running.isChecked())
|
||||
self.manager_settings.setValue('show/halted',
|
||||
self.show_halted.isChecked())
|
||||
self.manager_settings.setValue('show/network',
|
||||
self.show_network.isChecked())
|
||||
self.manager_settings.setValue('show/templates',
|
||||
self.show_templates.isChecked())
|
||||
self.manager_settings.setValue('show/standalone',
|
||||
self.show_standalone.isChecked())
|
||||
self.manager_settings.setValue('show/all', self.show_all.isChecked())
|
||||
|
||||
def save_sorting(self):
|
||||
self.manager_settings.setValue('view/sort_column',
|
||||
self.proxy.sortColumn())
|
||||
self.manager_settings.setValue('view/sort_order',
|
||||
self.proxy.sortOrder())
|
||||
|
||||
def invalidate(self):
|
||||
self.proxy.invalidate()
|
||||
self.table.resizeColumnsToContents()
|
||||
|
||||
def fill_cache(self):
|
||||
progress = QProgressDialog(
|
||||
self.tr(
|
||||
@ -1024,6 +1077,23 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow):
|
||||
if not self.manager_settings.value("view/toolbar_visible",
|
||||
defaultValue=True):
|
||||
self.action_toolbar.setChecked(False)
|
||||
if self.manager_settings.value("view/compactview",
|
||||
defaultValue="false") != "false":
|
||||
self.action_compact_view.setChecked(True)
|
||||
|
||||
# Restore show checkboxes
|
||||
self.show_running.setChecked(self.manager_settings.value(
|
||||
'show/running', "true") == "true")
|
||||
self.show_halted.setChecked(self.manager_settings.value(
|
||||
'show/halted', "true") == "true")
|
||||
self.show_network.setChecked(self.manager_settings.value(
|
||||
'show/network', "true") == "true")
|
||||
self.show_templates.setChecked(self.manager_settings.value(
|
||||
'show/templates', "true") == "true")
|
||||
self.show_standalone.setChecked(self.manager_settings.value(
|
||||
'show/standalone', "true") == "true")
|
||||
self.show_all.setChecked(self.manager_settings.value(
|
||||
'show/all', "true") == "true")
|
||||
|
||||
# load last window size
|
||||
self.resize(self.manager_settings.value("window_size",
|
||||
@ -1389,6 +1459,9 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow):
|
||||
"\nError: {}".format(str(ex))))
|
||||
return
|
||||
|
||||
def closeEvent(self, _):
|
||||
self.save_showing()
|
||||
|
||||
# noinspection PyArgumentList
|
||||
@pyqtSlot(name='on_action_settings_triggered')
|
||||
def action_settings_triggered(self):
|
||||
@ -1515,6 +1588,14 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow):
|
||||
def action_exit_triggered(self):
|
||||
self.close()
|
||||
|
||||
def set_compactview(self, checked):
|
||||
if checked:
|
||||
self.toolbar.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
||||
else:
|
||||
self.toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
|
||||
if self.settings_loaded:
|
||||
self.manager_settings.setValue('view/compactview', checked)
|
||||
|
||||
def showhide_menubar(self, checked):
|
||||
self.menubar.setVisible(checked)
|
||||
if not checked:
|
||||
|
@ -459,7 +459,7 @@ def format_dependencies_list(dependencies):
|
||||
|
||||
|
||||
def loop_shutdown():
|
||||
pending = asyncio.Task.all_tasks()
|
||||
pending = asyncio.all_tasks()
|
||||
for task in pending:
|
||||
with suppress(asyncio.CancelledError):
|
||||
task.cancel()
|
||||
|
@ -52,23 +52,6 @@
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<layout class="QHBoxLayout" name="searchContainer">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Search:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QTableView" name="table">
|
||||
<property name="minimumSize">
|
||||
@ -108,7 +91,7 @@
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
@ -236,6 +219,103 @@ Template</string>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QHBoxLayout" name="searchContainer">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Search:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="show_label">
|
||||
<property name="text">
|
||||
<string>Show:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="show_running">
|
||||
<property name="text">
|
||||
<string>Running</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="show_halted">
|
||||
<property name="text">
|
||||
<string>Halted</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="show_network">
|
||||
<property name="text">
|
||||
<string>Network</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="show_templates">
|
||||
<property name="text">
|
||||
<string>Templates</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="show_standalone">
|
||||
<property name="text">
|
||||
<string>Standalone</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="show_all">
|
||||
<property name="text">
|
||||
<string>All</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
@ -889,6 +969,14 @@ Template</string>
|
||||
<string>Open a secure Xen console in the qube. Useful chiefly for debugging purposes: for normal operation, use "Run Terminal" from the Domains widget. </string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_compact_view">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Compact View</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../resources.qrc"/>
|
||||
|
Loading…
Reference in New Issue
Block a user