diff --git a/Makefile b/Makefile
index ab0570e..df8c4b2 100644
--- a/Makefile
+++ b/Makefile
@@ -20,6 +20,8 @@ res:
pyuic4 -o qubesmanager/ui_newfwruledlg.py newfwruledlg.ui
pyuic4 -o qubesmanager/ui_multiselectwidget.py multiselectwidget.ui
pyuic4 -o qubesmanager/ui_settingsdlg.py settingsdlg.ui
+ pyuic4 -o qubesmanager/ui_restoredlg.py restoredlg.ui
+ pyuic4 -o qubesmanager/ui_backupdlg.py backupdlg.ui
update-repo-current:
ln -f $(RPMS_DIR)/x86_64/qubes-manager-*$(VERSION)*.rpm ../yum/current-release/current/dom0/rpm/
diff --git a/backupdlg.ui b/backupdlg.ui
new file mode 100644
index 0000000..33de66b
--- /dev/null
+++ b/backupdlg.ui
@@ -0,0 +1,218 @@
+
+
+ Backup
+
+
+
+ 0
+ 0
+ 700
+ 399
+
+
+
+ Qubes Backup VMs
+
+
+
+
+
+ QWizard::NoBackButtonOnLastPage|QWizard::NoBackButtonOnStartPage
+
+
+
+ -
+
+
+
+ 12
+ 75
+ false
+ true
+ false
+
+
+
+ Select VMs to backup:
+
+
+
+
+
+
+
+ -
+
+
+
+ 12
+ 75
+ false
+ true
+ false
+
+
+
+ Select backup destination directory:
+
+
+
+ -
+
+
+ Device
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
-
+
+ dev1
+
+
+ -
+
+ longdeviceblablabla
+
+
+ -
+
+ dev2
+
+
+ -
+
+ dev3
+
+
+
+
+ -
+
+
+ Backup directory:
+
+
+
+ -
+
+
+ -
+
+
+ ...
+
+
+
+
+
+
+
+ -
+
+
+
+ 12
+ 75
+ false
+ true
+ false
+
+
+
+ You're about to perform the following actions:
+
+
+
+ -
+
+
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A lot of info<br />A lot of info<br />A lot of info<br />A lot of info<br />A lot of info<br />A lot of info<br />A lot of info A lot of info A lot of info A lot of info A lot of info A lot of info</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A lot of info A lot of info A lot of info A lot of info A lot of info A lot of info</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A lot of info A lot of info A lot of info A lot of info A lot of info A lot of info</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A lot of info A lot of info A lot of info A lot of info A lot of info A lot of info</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A lot of info A lot of info A lot of info A lot of info A lot of info A lot of info<br />A lot of info</p></body></html>
+
+
+
+ -
+
+
+
+ 12
+ 75
+ false
+ true
+ false
+
+
+
+ To continue press Next.
+
+
+
+
+
+
+
+ -
+
+
+
+ 12
+ 75
+ false
+ true
+ false
+
+
+
+ Backup in progress...
+
+
+
+ -
+
+
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A lot of info<br />A lot of info<br />A lot of info<br />A lot of info<br />A lot of info<br />A lot of info<br />A lot of info A lot of info A lot of info A lot of info A lot of info A lot of info</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A lot of info A lot of info A lot of info A lot of info A lot of info A lot of info</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A lot of info A lot of info A lot of info A lot of info A lot of info A lot of info</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A lot of info A lot of info A lot of info A lot of info A lot of info A lot of info</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A lot of info A lot of info A lot of info A lot of info A lot of info A lot of info<br />A lot of info</p></body></html>
+
+
+
+ -
+
+
+ 24
+
+
+ Qt::AlignCenter
+
+
+ false
+
+
+
+
+
+
+
+
+
diff --git a/mainwindow.ui b/mainwindow.ui
index 79d8597..59e2da6 100644
--- a/mainwindow.ui
+++ b/mainwindow.ui
@@ -128,19 +128,6 @@
Name
-
-
- 50
- false
-
-
-
-
- 0
- 0
- 0
-
-
@@ -199,6 +186,8 @@
Options
+
+
diff --git a/qubesmanager/backup.py b/qubesmanager/backup.py
new file mode 100644
index 0000000..8d223f1
--- /dev/null
+++ b/qubesmanager/backup.py
@@ -0,0 +1,136 @@
+#!/usr/bin/python2.6
+#
+# The Qubes OS Project, http://www.qubes-os.org
+#
+# Copyright (C) 2012 Agnieszka Kostrzewa
+# Copyright (C) 2012 Marek Marczykowski
+#
+# 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 sys
+import os
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+
+from qubes.qubes import QubesVmCollection
+from qubes.qubes import QubesException
+from qubes.qubes import QubesDaemonPidfile
+from qubes.qubes import QubesHost
+
+import qubesmanager.resources_rc
+
+from pyinotify import WatchManager, Notifier, ThreadedNotifier, EventsCodes, ProcessEvent
+
+import subprocess
+import time
+import threading
+from operator import itemgetter
+
+from ui_backupdlg import *
+from multiselectwidget import *
+
+
+
+class BackupVMsWindow(Ui_Backup, QWizard):
+
+ def __init__(self, parent=None):
+ super(BackupVMsWindow, self).__init__(parent)
+
+ self.setupUi(self)
+
+ self.selectVMsWidget = MultiSelectWidget(self)
+ self.verticalLayout.insertWidget(1, self.selectVMsWidget)
+
+ self.selectVMsWidget.available_list.addItem("netVM1")
+ self.selectVMsWidget.available_list.addItem("appVM1")
+ self.selectVMsWidget.available_list.addItem("appVM2")
+ self.selectVMsWidget.available_list.addItem("templateVM1")
+
+ self.connect(self, SIGNAL("currentIdChanged(int)"), self.current_page_changed)
+
+
+
+ def reject(self):
+ self.done(0)
+
+ def save_and_apply(self):
+ pass
+
+ @pyqtSlot(name='on_selectPathButton_clicked')
+ def selectPathButton_clicked(self):
+ self.path = self.pathLineEdit.text()
+ newPath = QFileDialog.getExistingDirectory(self, 'Select backup directory.')
+ if newPath:
+ self.pathLineEdit.setText(newPath)
+ self.path = newPath
+
+ def current_page_changed(self, id):
+ self.button(self.CancelButton).setDisabled(id==3)
+
+
+# Bases on the original code by:
+# Copyright (c) 2002-2007 Pascal Varet
+
+def handle_exception( exc_type, exc_value, exc_traceback ):
+ import sys
+ import os.path
+ import traceback
+
+ filename, line, dummy, dummy = traceback.extract_tb( exc_traceback ).pop()
+ filename = os.path.basename( filename )
+ error = "%s: %s" % ( exc_type.__name__, exc_value )
+
+ QMessageBox.critical(None, "Houston, we have a problem...",
+ "Whoops. A critical error has occured. This is most likely a bug "
+ "in Qubes Restore VMs application.
"
+ "%s" % error +
+ "at line %d of file %s.
"
+ % ( line, filename ))
+
+
+
+
+def main():
+
+ global qubes_host
+ qubes_host = QubesHost()
+
+ global app
+ app = QApplication(sys.argv)
+ app.setOrganizationName("The Qubes Project")
+ app.setOrganizationDomain("http://qubes-os.org")
+ app.setApplicationName("Qubes Restore VMs")
+
+ sys.excepthook = handle_exception
+
+ qvm_collection = QubesVmCollection()
+ qvm_collection.lock_db_for_reading()
+ qvm_collection.load()
+ qvm_collection.unlock_db()
+
+ global backup_window
+ backup_window = BackupVMsWindow()
+
+ backup_window.show()
+
+ app.exec_()
+ app.exit()
+
+
+
+if __name__ == "__main__":
+ main()
diff --git a/qubesmanager/main.py b/qubesmanager/main.py
index 76abb11..144a09a 100755
--- a/qubesmanager/main.py
+++ b/qubesmanager/main.py
@@ -39,6 +39,9 @@ import qubesmanager.resources_rc
import ui_newappvmdlg
from ui_mainwindow import *
from appmenu_select import AppmenuSelectWindow
+from settings import VMSettingsWindow
+from restore import RestoreVMsWindow
+from backup import BackupVMsWindow
from firewall import EditFwRulesDlg, QubesFirewallRulesModel
@@ -601,7 +604,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
for vm_row in self.vms_in_table:
vm_row.update(self.counter)
- self.table_selection_changed()
+ #self.table_selection_changed()
if not out_of_schedule:
self.counter += 1
@@ -615,13 +618,13 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
self.centralwidget.layout().contentsMargins().right()
self.table.setFixedWidth( width )
- self.setFixedWidth( width)
def table_selection_changed (self):
+
vm = self.get_selected_vm()
# Update available actions:
-
+ self.action_settings.setEnabled(True)
self.action_removevm.setEnabled(not vm.installed_by_rpm and not vm.last_power_state)
self.action_resumevm.setEnabled(not vm.last_power_state)
self.action_pausevm.setEnabled(vm.last_power_state and vm.qid != 0)
@@ -878,6 +881,13 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
self.shutdown_monitor[vm.qid] = VmShutdownMonitor (vm)
QTimer.singleShot (vm_shutdown_timeout, self.shutdown_monitor[vm.qid].check_if_vm_has_shutdown)
+ @pyqtSlot(name='on_action_settings_triggered')
+ def action_settings_triggered(self):
+ vm = self.get_selected_vm()
+ settings_window = VMSettingsWindow(vm)
+ settings_window.exec_()
+
+
@pyqtSlot(name='on_action_appmenus_triggered')
def action_appmenus_triggered(self):
vm = self.get_selected_vm()
@@ -931,6 +941,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
self.show_inactive_vms = self.action_showallvms.isChecked()
self.mark_table_for_update()
self.update_table(out_of_schedule = True)
+ self.set_table_geom_height()
@pyqtSlot(name='on_action_editfwrules_triggered')
def action_editfwrules_triggered(self):
@@ -948,6 +959,18 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
model.apply_rules()
+ @pyqtSlot(name='on_action_restore_triggered')
+ def action_restore_triggered(self):
+ restore_window = RestoreVMsWindow()
+ restore_window.exec_()
+
+ @pyqtSlot(name='on_action_backup_triggered')
+ def action_backup_triggered(self):
+ backup_window = BackupVMsWindow()
+ backup_window.exec_()
+
+
+
def showhide_collumn(self, col_num, show):
self.table.setColumnHidden( col_num, not show)
self.update_table_columns()
diff --git a/qubesmanager/restore.py b/qubesmanager/restore.py
index 247f470..9371f85 100644
--- a/qubesmanager/restore.py
+++ b/qubesmanager/restore.py
@@ -60,6 +60,7 @@ class RestoreVMsWindow(Ui_Restore, QWizard):
self.selectVMsWidget.available_list.addItem("appVM2")
self.selectVMsWidget.available_list.addItem("templateVM1")
+ self.connect(self, SIGNAL("currentIdChanged(int)"), self.current_page_changed)
def reject(self):
self.done(0)
@@ -67,6 +68,9 @@ class RestoreVMsWindow(Ui_Restore, QWizard):
def save_and_apply(self):
pass
+ def current_page_changed(self, id):
+ self.button(self.CancelButton).setDisabled(id==3)
+
@pyqtSlot(name='on_selectPathButton_clicked')
def selectPathButton_clicked(self):
self.path = self.pathLineEdit.text()
diff --git a/restoredlg.ui b/restoredlg.ui
index a37807d..88360e1 100644
--- a/restoredlg.ui
+++ b/restoredlg.ui
@@ -16,6 +16,9 @@
+
+ QWizard::NoBackButtonOnLastPage|QWizard::NoBackButtonOnStartPage
+
-
@@ -228,7 +231,55 @@ p, li { white-space: pre-wrap; }
- To accept press Finish.
+ To continue press Next.
+
+
+
+
+
+
+
+ -
+
+
+
+ 12
+ 75
+ false
+ true
+ false
+
+
+
+ Restore in progress...
+
+
+
+ -
+
+
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A lot of info<br />A lot of info<br />A lot of info<br />A lot of info<br />A lot of info<br />A lot of info<br />A lot of info A lot of info A lot of info A lot of info A lot of info A lot of info</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A lot of info A lot of info A lot of info A lot of info A lot of info A lot of info</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A lot of info A lot of info A lot of info A lot of info A lot of info A lot of info</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A lot of info A lot of info A lot of info A lot of info A lot of info A lot of info</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A lot of info A lot of info A lot of info A lot of info A lot of info A lot of info<br />A lot of info</p></body></html>
+
+
+
+ -
+
+
+ 24
+
+
+ Qt::AlignCenter
+
+
+ false