Restore dialog

This commit is contained in:
Agnieszka Kostrzewa 2012-02-22 06:09:25 +01:00
parent df02ed2aa4
commit 6d0a247997
5 changed files with 384 additions and 243 deletions

View File

@ -47,6 +47,7 @@ from string import replace
from ui_backupdlg import * from ui_backupdlg import *
from multiselectwidget import * from multiselectwidget import *
from backup_utils import *
class BackupVMsWindow(Ui_Backup, QWizard): class BackupVMsWindow(Ui_Backup, QWizard):
@ -63,6 +64,7 @@ class BackupVMsWindow(Ui_Backup, QWizard):
self.qvm_collection = qvm_collection self.qvm_collection = qvm_collection
self.blk_manager = blk_manager self.blk_manager = blk_manager
self.dev_mount_path = None
self.backup_dir = None self.backup_dir = None
self.func_output = [] self.func_output = []
@ -91,7 +93,7 @@ class BackupVMsWindow(Ui_Backup, QWizard):
self.select_vms_page.connect(self.select_vms_widget, SIGNAL("selected_changed()"), SIGNAL("completeChanged()")) self.select_vms_page.connect(self.select_vms_widget, SIGNAL("selected_changed()"), SIGNAL("completeChanged()"))
self.__fill_vms_list__() self.__fill_vms_list__()
self.__fill_devs_list__() fill_devs_list(self)
def __fill_vms_list__(self): def __fill_vms_list__(self):
for vm in self.qvm_collection.values(): for vm in self.qvm_collection.values():
@ -110,112 +112,14 @@ class BackupVMsWindow(Ui_Backup, QWizard):
self.to_backup.append(vm.name) self.to_backup.append(vm.name)
self.select_vms_widget.available_list.addItem(vm.name) self.select_vms_widget.available_list.addItem(vm.name)
def __fill_devs_list__(self):
self.dev_combobox.clear()
self.dev_combobox.addItem("None")
for a in self.blk_manager.attached_devs:
if self.blk_manager.attached_devs[a]['attached_to']['vm'] == self.vm.name :
att = a + " " + unicode(self.blk_manager.attached_devs[a]['size']) + " " + self.blk_manager.attached_devs[a]['desc']
self.dev_combobox.addItem(att, QVariant(a))
for a in self.blk_manager.free_devs:
att = a + " " + unicode(self.blk_manager.free_devs[a]['size']) + " " + self.blk_manager.free_devs[a]['desc']
self.dev_combobox.addItem(att, QVariant(a))
self.dev_combobox.setCurrentIndex(0) #current selected is null ""
self.prev_dev_idx = 0
self.dir_line_edit.clear()
self.dir_line_edit.setEnabled(False)
self.select_path_button.setEnabled(False)
def __check_if_mounted__(self, dev_path):
mounts_file = open("/proc/mounts")
for m in list(mounts_file):
if m.startswith(dev_path):
print m
return m.split(" ")[1]
return None
def __mount_device__(self, dev_path):
try:
mount_dir_name = "backup" + replace(str(datetime.now()),' ', '-').split(".")[0]
pmount_cmd = ["pmount", dev_path, mount_dir_name]
res = subprocess.check_call(pmount_cmd)
print "pmount device res: ", res
except Exception as ex:
QMessageBox.warning (None, "Error mounting selected device!", "ERROR: {0}".format(ex))
return None
if res == 0:
self.dev_mount_path = "/media/"+mount_dir_name
return self.dev_mount_path
def __umount_device__(self, dev_mount_path):
try:
pumount_cmd = ["pumount", dev_mount_path]
res = subprocess.check_call(pumount_cmd)
print "pumount device res: ", res
except Exception as ex:
QMessageBox.warning (None, "Could not unmount backup device!", "ERROR: {0}".format(ex))
def __enable_dir_line_edit__(self, boolean):
self.dir_line_edit.setEnabled(boolean)
self.select_path_button.setEnabled(boolean)
def dev_combobox_activated(self, idx): def dev_combobox_activated(self, idx):
print self.dev_combobox.currentText() dev_combobox_activated(self, idx)
if idx == self.prev_dev_idx: #nothing has changed
return
#there was a change
self.prev_dev_idx = idx
self.dir_line_edit.setText("")
self.backup_dir = None
self.dev_mount_path = None
self.__enable_dir_line_edit__(False)
if self.dev_combobox.currentText() != "None": #An existing device chosen
dev_name = str(self.dev_combobox.itemData(idx).toString())
if dev_name in self.blk_manager.free_devs:
if dev_name.startswith(self.vm.name): # originally attached to dom0
dev_path = "/dev/"+dev_name.split(":")[1]
print "device from dom0 - no need to attach"
else: # originally attached to another domain, eg. usbvm
print "device from " + dev_name.split(":")[0]
#attach it to dom0, then treat it as an attached device
self.blk_manager.attach_device(self.vm, dev_name)
if dev_name in self.blk_manager.attached_devs: #is attached to dom0
print "device attached as " + self.blk_manager.attached_devs[dev_name]['attached_to']['frontend']
assert self.blk_manager.attached_devs[dev_name]['attached_to']['vm'] == self.vm.name
dev_path = "/dev/" + self.blk_manager.attached_devs[dev_name]['attached_to']['frontend']
#check if device mounted
self.dev_mount_path = self.__check_if_mounted__(dev_path)
if self.dev_mount_path != None:
self.__enable_dir_line_edit__(True)
else:
self.dev_mount_path = self.__mount_device__(dev_path)
if self.dev_mount_path != None:
self.__enable_dir_line_edit__(True)
self.select_dir_page.emit(SIGNAL("completeChanged()"))
@pyqtSlot(name='on_select_path_button_clicked') @pyqtSlot(name='on_select_path_button_clicked')
def select_path_button_clicked(self): def select_path_button_clicked(self):
self.backup_dir = self.dir_line_edit.text() select_path_button_clicked(self)
file_dialog = QFileDialog()
file_dialog.setReadOnly(True)
new_path = file_dialog.getExistingDirectory(self, "Select backup directory.", self.dev_mount_path)
if new_path:
self.dir_line_edit.setText(new_path)
self.backup_dir = new_path
self.select_dir_page.emit(SIGNAL("completeChanged()"))
def validateCurrentPage(self): def validateCurrentPage(self):
if self.currentPage() is self.select_vms_page: if self.currentPage() is self.select_vms_page:
@ -228,18 +132,15 @@ class BackupVMsWindow(Ui_Backup, QWizard):
self.func_output.append(s) self.func_output.append(s)
def update_progress_bar(self, value): def update_progress_bar(self, value):
print "progress bar value: ", value
self.emit(SIGNAL("backup_progress(int)"), value) self.emit(SIGNAL("backup_progress(int)"), value)
def __do_backup__(self, thread_monitor): def __do_backup__(self, thread_monitor):
print "doiing backup"
msg = [] msg = []
try: try:
qubesutils.backup_do(str(self.backup_dir), self.files_to_backup, self.update_progress_bar) qubesutils.backup_do(str(self.backup_dir), self.files_to_backup, self.update_progress_bar)
#simulate_long_lasting_proces(10, self.update_progress_bar) #simulate_long_lasting_proces(10, self.update_progress_bar)
except Exception as ex: except Exception as ex:
print "got exception from backup"
msg.append(str(ex)) msg.append(str(ex))
if len(msg) > 0 : if len(msg) > 0 :
@ -252,25 +153,17 @@ class BackupVMsWindow(Ui_Backup, QWizard):
if self.currentPage() is self.confirm_page: if self.currentPage() is self.confirm_page:
del self.func_output[:] del self.func_output[:]
self.files_to_backup = qubesutils.backup_prepare(str(self.backup_dir), exclude_list = self.excluded, print_callback = self.gather_output) self.files_to_backup = qubesutils.backup_prepare(str(self.backup_dir), exclude_list = self.excluded, print_callback = self.gather_output)
for i in self.excluded:
print i
self.textEdit.setReadOnly(True) self.textEdit.setReadOnly(True)
self.textEdit.setFontFamily("Monospace") self.textEdit.setFontFamily("Monospace")
self.textEdit.setText("\n".join(self.func_output)) self.textEdit.setText("\n".join(self.func_output))
for i in self.func_output:
print i
for s in self.files_to_backup:
print s
elif self.currentPage() is self.commit_page: elif self.currentPage() is self.commit_page:
self.button(self.CancelButton).setDisabled(True) self.button(self.CancelButton).setDisabled(True)
self.button(self.FinishButton).setDisabled(True) self.button(self.FinishButton).setDisabled(True)
print "butons disabled"
self.thread_monitor = ThreadMonitor() self.thread_monitor = ThreadMonitor()
thread = threading.Thread (target= self.__do_backup__ , args=(self.thread_monitor,)) thread = threading.Thread (target= self.__do_backup__ , args=(self.thread_monitor,))
thread.daemon = True thread.daemon = True
print "will start thread"
thread.start() thread.start()
while not self.thread_monitor.is_finished(): while not self.thread_monitor.is_finished():
@ -280,25 +173,16 @@ class BackupVMsWindow(Ui_Backup, QWizard):
if not self.thread_monitor.success: if not self.thread_monitor.success:
QMessageBox.warning (None, "Backup error!", "ERROR: {1}".format(self.vm.name, self.thread_monitor.error_msg)) QMessageBox.warning (None, "Backup error!", "ERROR: {1}".format(self.vm.name, self.thread_monitor.error_msg))
self.__umount_device__(self.dev_mount_path) umount_device(self.dev_mount_path)
self.button(self.FinishButton).setEnabled(True) self.button(self.FinishButton).setEnabled(True)
def has_selected_vms(self): def has_selected_vms(self):
print "isComplete called"
return self.select_vms_widget.selected_list.count() > 0 return self.select_vms_widget.selected_list.count() > 0
def has_selected_dir(self): def has_selected_dir(self):
return self.backup_dir != None return self.backup_dir != None
def simulate_long_lasting_proces(period, progress_callback):
for i in range(period):
progress_callback((i*100)/period)
time.sleep(1)
progress_callback(100)
return 0
# Bases on the original code by: # Bases on the original code by:

View File

@ -0,0 +1,159 @@
#!/usr/bin/python2.6
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2012 Agnieszka Kostrzewa <agnieszka.kostrzewa@gmail.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 sys
import os
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from pyinotify import WatchManager, Notifier, ThreadedNotifier, EventsCodes, ProcessEvent
import subprocess
import time
from thread_monitor import *
from datetime import datetime
from string import replace
def check_if_mounted(dev_path):
mounts_file = open("/proc/mounts")
for m in list(mounts_file):
if m.startswith(dev_path):
return m.split(" ")[1]
return None
def mount_device(dev_path):
try:
mount_dir_name = "backup" + replace(str(datetime.now()),' ', '-').split(".")[0]
pmount_cmd = ["pmount", dev_path, mount_dir_name]
res = subprocess.check_call(pmount_cmd)
except Exception as ex:
QMessageBox.warning (None, "Error mounting selected device!", "ERROR: {0}".format(ex))
return None
if res == 0:
dev_mount_path = "/media/"+mount_dir_name
return dev_mount_path
return None
def umount_device(dev_mount_path):
try:
pumount_cmd = ["pumount", dev_mount_path]
res = subprocess.check_call(pumount_cmd)
if res == 0:
dev_mount_path = None
except Exception as ex:
QMessageBox.warning (None, "Could not unmount backup device!", "ERROR: {0}".format(ex))
return dev_mount_path
def fill_devs_list(dialog):
dialog.dev_combobox.clear()
dialog.dev_combobox.addItem("None")
for a in dialog.blk_manager.attached_devs:
if dialog.blk_manager.attached_devs[a]['attached_to']['vm'] == dialog.vm.name :
att = a + " " + unicode(dialog.blk_manager.attached_devs[a]['size']) + " " + dialog.blk_manager.attached_devs[a]['desc']
dialog.dev_combobox.addItem(att, QVariant(a))
for a in dialog.blk_manager.free_devs:
att = a + " " + unicode(dialog.blk_manager.free_devs[a]['size']) + " " + dialog.blk_manager.free_devs[a]['desc']
dialog.dev_combobox.addItem(att, QVariant(a))
dialog.dev_combobox.setCurrentIndex(0) #current selected is null ""
dialog.prev_dev_idx = 0
dialog.dir_line_edit.clear()
dialog.dir_line_edit.setEnabled(False)
dialog.select_path_button.setEnabled(False)
def enable_dir_line_edit(dialog, boolean):
dialog.dir_line_edit.setEnabled(boolean)
dialog.select_path_button.setEnabled(boolean)
def dev_combobox_activated(dialog, idx):
if idx == dialog.prev_dev_idx: #nothing has changed
return
#there was a change
dialog.dir_line_edit.setText("")
dialog.backup_dir = None
if dialog.dev_mount_path != None:
dialog.dev_mount_path = umount_device(dialog.dev_mount_path)
if dialog_dev_mount_path != None:
dialog.dev_combobox.setCurrentIndex(dialog.prev_dev_idx)
return
enable_dir_line_edit(dialog, False)
if dialog.dev_combobox.currentText() != "None": #An existing device chosen
dev_name = str(dialog.dev_combobox.itemData(idx).toString())
if dev_name in dialog.blk_manager.free_devs:
if dev_name.startswith(dialog.vm.name): # originally attached to dom0
dev_path = "/dev/"+dev_name.split(":")[1]
else: # originally attached to another domain, eg. usbvm
#attach it to dom0, then treat it as an attached device
dialog.blk_manager.attach_device(dialog.vm, dev_name)
if dev_name in dialog.blk_manager.attached_devs: #is attached to dom0
assert dialog.blk_manager.attached_devs[dev_name]['attached_to']['vm'] == dialog.vm.name
dev_path = "/dev/" + dialog.blk_manager.attached_devs[dev_name]['attached_to']['frontend']
#check if device mounted
dialog.dev_mount_path = check_if_mounted(dev_path)
if dialog.dev_mount_path != None:
enable_dir_line_edit(dialog, True)
else:
dialog.dev_mount_path = mount_device(dev_path)
if dialog.dev_mount_path != None:
enable_dir_line_edit(dialog, True)
else:
dialog.dev_combobox.setCurrentIndex(0) #if couldn't mount - set current device to "None"
dialog.prev_dev_idx = idx
dialog.select_dir_page.emit(SIGNAL("completeChanged()"))
def select_path_button_clicked(dialog):
dialog.backup_dir = dialog.dir_line_edit.text()
file_dialog = QFileDialog()
file_dialog.setReadOnly(True)
new_path = file_dialog.getExistingDirectory(dialog, "Select backup directory.", dialog.dev_mount_path)
if new_path:
dialog.dir_line_edit.setText(new_path)
dialog.backup_dir = new_path
dialog.select_dir_page.emit(SIGNAL("completeChanged()"))
def simulate_long_lasting_proces(period, progress_callback):
for i in range(period):
progress_callback((i*100)/period)
time.sleep(1)
progress_callback(100)
return 0

View File

@ -1083,7 +1083,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
@pyqtSlot(name='on_action_restore_triggered') @pyqtSlot(name='on_action_restore_triggered')
def action_restore_triggered(self): def action_restore_triggered(self):
restore_window = RestoreVMsWindow() restore_window = RestoreVMsWindow(app, self.qvm_collection, self.blk_manager)
restore_window.exec_() restore_window.exec_()
@pyqtSlot(name='on_action_backup_triggered') @pyqtSlot(name='on_action_backup_triggered')

View File

@ -30,54 +30,197 @@ from qubes.qubes import QubesVmCollection
from qubes.qubes import QubesException from qubes.qubes import QubesException
from qubes.qubes import QubesDaemonPidfile from qubes.qubes import QubesDaemonPidfile
from qubes.qubes import QubesHost from qubes.qubes import QubesHost
from qubes.qubes import qubes_base_dir
import qubesmanager.resources_rc import qubesmanager.resources_rc
from pyinotify import WatchManager, Notifier, ThreadedNotifier, EventsCodes, ProcessEvent from pyinotify import WatchManager, Notifier, ThreadedNotifier, EventsCodes, ProcessEvent
import subprocess import subprocess
import time import time
import threading
from operator import itemgetter from operator import itemgetter
from thread_monitor import *
from qubes import qubesutils
from ui_restoredlg import * from ui_restoredlg import *
from multiselectwidget import * from multiselectwidget import *
from backup_utils import *
class RestoreVMsWindow(Ui_Restore, QWizard): class RestoreVMsWindow(Ui_Restore, QWizard):
def __init__(self, parent=None): __pyqtSignals__ = ("restore_progress(int)",)
def __init__(self, app, qvm_collection, blk_manager, parent=None):
super(RestoreVMsWindow, self).__init__(parent) super(RestoreVMsWindow, self).__init__(parent)
self.app = app
self.qvm_collection = qvm_collection
self.blk_manager = blk_manager
self.dev_mount_path = None
self.backup_dir = None
self.restore_options = None
self.backup_vms_list = None
self.func_output = []
self.excluded = {}
for vm in self.qvm_collection.values():
if vm.qid == 0:
self.vm = vm
break;
assert self.vm != None
self.setupUi(self) self.setupUi(self)
self.selectVMsWidget = MultiSelectWidget(self) self.select_vms_widget = MultiSelectWidget(self)
self.selectVMsLayout.insertWidget(1, self.selectVMsWidget) self.select_vms_layout.insertWidget(1, self.select_vms_widget)
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) self.connect(self, SIGNAL("currentIdChanged(int)"), self.current_page_changed)
self.connect(self.dev_combobox, SIGNAL("activated(int)"), self.dev_combobox_activated)
self.connect(self, SIGNAL("restore_progress(QString)"), self.commit_text_edit.append)
def reject(self): self.select_dir_page.isComplete = self.has_selected_dir
self.done(0) self.select_vms_page.isComplete = self.has_selected_vms
#FIXME
#this causes to run isComplete() twice, I don't know why
self.select_vms_page.connect(self.select_vms_widget, SIGNAL("selected_changed()"), SIGNAL("completeChanged()"))
fill_devs_list(self)
self.__init_restore_options__()
def dev_combobox_activated(self, idx):
dev_combobox_activated(self, idx)
@pyqtSlot(name='on_select_path_button_clicked')
def select_path_button_clicked(self):
select_path_button_clicked(self)
def on_ignore_missing_toggled(self, checked):
self.restore_options['use-default-template'] = checked
self.restore_options['use-default-netvm'] = checked
def on_ignore_uname_mismatch_toggled(self, checked):
self.restore_options['ignore-username-mismatch'] = checked
def on_skip_dom0_toggled(self, checked):
self.restore_options['dom0-home'] = checked
def __fill_vms_list__(self):
if self.backup_vms_list != None:
return
self.select_vms_widget.selected_list.clear()
self.select_vms_widget.available_list.clear()
self.vms_to_restore = qubesutils.backup_restore_prepare(str(self.backup_dir), self.restore_options, self.qvm_collection)
for vmname in self.vms_to_restore:
self.select_vms_widget.available_list.addItem(vmname)
def __init_restore_options__(self):
if not self.restore_options:
self.restore_options = {}
qubesutils.backup_restore_set_defaults(self.restore_options)
if 'use-default-template' in self.restore_options and 'use-default-netvm' in self.restore_options:
val = self.restore_options['use-default-template'] and self.restore_options['use-default-netvm']
self.ignore_missing.setChecked(val)
else:
self.ignore_missing.setChecked(False)
if 'ignore-username-mismatch' in self.restore_options:
self.ignore_uname_mismatch.setChecked(self.restore_options['ignore-username-mismatch'])
if 'dom0-home' in self.restore_options:
self.skip_dom0.setChecked(self.restore_options['dom0-home'])
def gather_output(self, s):
self.func_output.append(s)
def restore_error_output(self, s):
self.emit(SIGNAL("restore_progress(QString)"), '<font color="red">{0}</font>'.format(s))
def restore_output(self, s):
self.emit(SIGNAL("restore_progress(QString)"),'<font color="black">{0}</font>'.format(s))
def __do_restore__(self, thread_monitor):
err_msg = []
self.qvm_collection.lock_db_for_writing()
try:
qubesutils.backup_restore_do(str(self.backup_dir), self.vms_to_restore, self.qvm_collection, self.restore_output, self.restore_error_output)
except Exception as ex:
err_msg.append(str(ex))
self.qvm_collection.unlock_db()
if len(err_msg) > 0 :
thread_monitor.set_error_msg('\n'.join(err_msg))
self.emit(SIGNAL("restore_progress(QString)"),'<b><font color="red">{0}</font></b>'.format("Finished with errors!"))
else:
self.emit(SIGNAL("restore_progress(QString)"),'<font color="green">{0}</font>'.format("Finished successfully!"))
thread_monitor.set_finished()
def save_and_apply(self):
pass
def current_page_changed(self, id): def current_page_changed(self, id):
self.button(self.CancelButton).setDisabled(id==3)
@pyqtSlot(name='on_selectPathButton_clicked') if self.currentPage() is self.select_vms_page:
def selectPathButton_clicked(self): self.__fill_vms_list__()
self.path = self.pathLineEdit.text()
newPath = QFileDialog.getExistingDirectory(self, 'Select backup directory.') elif self.currentPage() is self.confirm_page:
if newPath: for v in self.excluded:
self.pathLineEdit.setText(newPath) self.vms_to_restore[v] = self.excluded[v]
self.path = newPath self.excluded = {}
for i in range(self.select_vms_widget.available_list.count()):
vmname = self.select_vms_widget.available_list.item(i).text()
self.excluded[str(vmname)] = self.vms_to_restore[str(vmname)]
del self.vms_to_restore[str(vmname)]
del self.func_output[:]
qubesutils.backup_restore_print_summary(self.vms_to_restore, print_callback = self.gather_output)
self.confirm_text_edit.setReadOnly(True)
self.confirm_text_edit.setFontFamily("Monospace")
self.confirm_text_edit.setText("\n".join(self.func_output))
elif self.currentPage() is self.commit_page:
self.button(self.CancelButton).setDisabled(True)
self.button(self.FinishButton).setDisabled(True)
self.thread_monitor = ThreadMonitor()
thread = threading.Thread (target= self.__do_restore__ , args=(self.thread_monitor,))
thread.daemon = True
thread.start()
while not self.thread_monitor.is_finished():
self.app.processEvents()
time.sleep (0.1)
#if not self.thread_monitor.success:
#QMessageBox.warning (None, "Backup error!", "ERROR: {1}".format(self.vm.name, self.thread_monitor.error_msg))
umount_device(self.dev_mount_path)
self.button(self.FinishButton).setEnabled(True)
def has_selected_dir(self):
return self.backup_dir != None
def has_selected_vms(self):
return self.select_vms_widget.selected_list.count() > 0
# Bases on the original code by: # Bases on the original code by:
# Copyright (c) 2002-2007 Pascal Varet <p.varet@gmail.com> # Copyright (c) 2002-2007 Pascal Varet <p.varet@gmail.com>

View File

@ -47,7 +47,7 @@
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="0" column="1">
<widget class="QComboBox" name="comboBox"> <widget class="QComboBox" name="dev_combobox">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed"> <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
@ -84,10 +84,10 @@
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QLineEdit" name="pathLineEdit"/> <widget class="QLineEdit" name="dir_line_edit"/>
</item> </item>
<item row="1" column="2"> <item row="1" column="2">
<widget class="QToolButton" name="selectPathButton"> <widget class="QToolButton" name="select_path_button">
<property name="text"> <property name="text">
<string>...</string> <string>...</string>
</property> </property>
@ -96,6 +96,48 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QGroupBox" name="options_groupbox">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="title">
<string>Restore options</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QCheckBox" name="ignore_missing">
<property name="toolTip">
<string>Ignore missing templates or netvms, restore VMs anyway.</string>
</property>
<property name="text">
<string>ignore missing</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="skip_dom0">
<property name="text">
<string>skip dom0</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="ignore_uname_mismatch">
<property name="toolTip">
<string>Ignore dom0 username mismatch while restoring homedir.</string>
</property>
<property name="text">
<string>ignore username mismatch</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item> <item>
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">
@ -114,72 +156,11 @@
<widget class="QWizardPage" name="select_vms_page"> <widget class="QWizardPage" name="select_vms_page">
<layout class="QVBoxLayout" name="verticalLayout_4"> <layout class="QVBoxLayout" name="verticalLayout_4">
<item> <item>
<widget class="QGroupBox" name="seletVMsGroupbox"> <widget class="QGroupBox" name="select_vms_groupbox">
<property name="title"> <property name="title">
<string>VMs to restore</string> <string>VMs to restore</string>
</property> </property>
<layout class="QVBoxLayout" name="selectVMsLayout"/> <layout class="QVBoxLayout" name="select_vms_layout"/>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="title">
<string>Restore options</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QCheckBox" name="skip_broken">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="toolTip">
<string>Do not restore VMs that have missing templates or netvms.</string>
</property>
<property name="text">
<string>skip broken</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="ignore_missing">
<property name="toolTip">
<string>Ignore missing templates or netvms, restore VMs anyway.</string>
</property>
<property name="text">
<string>ignore missing</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="skip_conflicting">
<property name="toolTip">
<string>Do not restore VMs that are already present on the host.</string>
</property>
<property name="text">
<string>skip conflicting</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="ignore_uname_mismatch">
<property name="toolTip">
<string>Ignore dom0 username mismatch while restoring homedir.</string>
</property>
<property name="text">
<string>ignore username mismatch</string>
</property>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
</layout> </layout>
@ -203,7 +184,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QTextEdit" name="textEdit"> <widget class="QTextEdit" name="confirm_text_edit">
<property name="html"> <property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt; <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt; &lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
@ -238,33 +219,7 @@ p, li { white-space: pre-wrap; }
<widget class="QWizardPage" name="commit_page"> <widget class="QWizardPage" name="commit_page">
<layout class="QVBoxLayout" name="verticalLayout_3"> <layout class="QVBoxLayout" name="verticalLayout_3">
<item> <item>
<widget class="QLabel" name="label_8"> <widget class="QTextEdit" name="commit_text_edit"/>
<property name="font">
<font>
<pointsize>9</pointsize>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
<underline>false</underline>
</font>
</property>
<property name="text">
<string>Restore in progress...</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="value">
<number>24</number>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>