Browse Source

Restore dialog

Agnieszka Kostrzewa 12 years ago
parent
commit
6d0a247997
5 changed files with 369 additions and 228 deletions
  1. 8 124
      qubesmanager/backup.py
  2. 159 0
      qubesmanager/backup_utils.py
  3. 1 1
      qubesmanager/main.py
  4. 166 23
      qubesmanager/restore.py
  5. 35 80
      restoredlg.ui

+ 8 - 124
qubesmanager/backup.py

@@ -47,6 +47,7 @@ from string import replace
 from ui_backupdlg import *
 from multiselectwidget import *
 
+from backup_utils import *
 
 
 class BackupVMsWindow(Ui_Backup, QWizard):
@@ -63,6 +64,7 @@ class BackupVMsWindow(Ui_Backup, QWizard):
         self.qvm_collection = qvm_collection
         self.blk_manager = blk_manager
 
+        self.dev_mount_path = None
         self.backup_dir = None
         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.__fill_vms_list__()
-        self.__fill_devs_list__()
+        fill_devs_list(self)
 
     def __fill_vms_list__(self):
         for vm in self.qvm_collection.values():
@@ -110,112 +112,14 @@ class BackupVMsWindow(Ui_Backup, QWizard):
             self.to_backup.append(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):
-        print self.dev_combobox.currentText()
-        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()"))
-
+        dev_combobox_activated(self, idx)
                    
 
     @pyqtSlot(name='on_select_path_button_clicked')
     def select_path_button_clicked(self):
-        self.backup_dir = self.dir_line_edit.text()
-        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()"))
+        select_path_button_clicked(self)
 
     def validateCurrentPage(self):
         if self.currentPage() is self.select_vms_page:
@@ -228,18 +132,15 @@ class BackupVMsWindow(Ui_Backup, QWizard):
         self.func_output.append(s)
 
     def update_progress_bar(self, value):
-        print "progress bar value: ", value
         self.emit(SIGNAL("backup_progress(int)"), value)
 
 
     def __do_backup__(self, thread_monitor):
-        print "doiing backup"
         msg = []
         try:
             qubesutils.backup_do(str(self.backup_dir), self.files_to_backup, self.update_progress_bar)
             #simulate_long_lasting_proces(10, self.update_progress_bar) 
         except Exception as ex:
-            print "got exception from backup"
             msg.append(str(ex))
 
         if len(msg) > 0 :
@@ -252,25 +153,17 @@ class BackupVMsWindow(Ui_Backup, QWizard):
         if self.currentPage() is self.confirm_page:
             del self.func_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.setFontFamily("Monospace")
             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:
             self.button(self.CancelButton).setDisabled(True)
             self.button(self.FinishButton).setDisabled(True)
-            print "butons disabled"
             self.thread_monitor = ThreadMonitor()
             thread = threading.Thread (target= self.__do_backup__ , args=(self.thread_monitor,))
             thread.daemon = True
-            print "will start thread"
             thread.start()
 
             while not self.thread_monitor.is_finished():
@@ -280,25 +173,16 @@ class BackupVMsWindow(Ui_Backup, QWizard):
             if not self.thread_monitor.success:
                 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)
-
  
     def has_selected_vms(self):
-        print "isComplete called"
         return self.select_vms_widget.selected_list.count() > 0
 
     def has_selected_dir(self):
         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:

+ 159 - 0
qubesmanager/backup_utils.py

@@ -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
+

+ 1 - 1
qubesmanager/main.py

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

+ 166 - 23
qubesmanager/restore.py

@@ -30,54 +30,197 @@ from qubes.qubes import QubesVmCollection
 from qubes.qubes import QubesException
 from qubes.qubes import QubesDaemonPidfile
 from qubes.qubes import QubesHost
-
+from qubes.qubes import qubes_base_dir
 import qubesmanager.resources_rc
 
 from pyinotify import WatchManager, Notifier, ThreadedNotifier, EventsCodes, ProcessEvent
 
 import subprocess
 import time
-import threading
 from operator import itemgetter
+from thread_monitor import *
+
+from qubes import qubesutils
 
 from ui_restoredlg import *
 from multiselectwidget import *
 
+from backup_utils import *
+
 
 
 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)
 
-        self.setupUi(self)
+        self.app = app
+        self.qvm_collection = qvm_collection
+        self.blk_manager = blk_manager
 
-        self.selectVMsWidget = MultiSelectWidget(self)
-        self.selectVMsLayout.insertWidget(1, self.selectVMsWidget)
+        self.dev_mount_path = None
+        self.backup_dir = None
+        self.restore_options = None
+        self.backup_vms_list = None
+        self.func_output = []
 
-        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.excluded = {}
+
+        for vm in self.qvm_collection.values():
+            if vm.qid == 0:
+                self.vm = vm
+                break;
         
+        assert self.vm != None
+
+        self.setupUi(self)
+
+        self.select_vms_widget = MultiSelectWidget(self)
+        self.select_vms_layout.insertWidget(1, self.select_vms_widget)
+
         self.connect(self, SIGNAL("currentIdChanged(int)"), self.current_page_changed)
-       
-    def reject(self):
-        self.done(0)
+        self.connect(self.dev_combobox, SIGNAL("activated(int)"), self.dev_combobox_activated)
+        self.connect(self, SIGNAL("restore_progress(QString)"), self.commit_text_edit.append)
+
+        self.select_dir_page.isComplete = self.has_selected_dir
+        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
 
-    def save_and_apply(self):
-        pass
+        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 current_page_changed(self, id):
-        self.button(self.CancelButton).setDisabled(id==3)
+
+        if self.currentPage() is self.select_vms_page:
+            self.__fill_vms_list__()
+
+        elif self.currentPage() is self.confirm_page:
+            for v in self.excluded:
+                self.vms_to_restore[v] = self.excluded[v]
+            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)
  
-    @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 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:
 # Copyright (c) 2002-2007 Pascal Varet <p.varet@gmail.com>

+ 35 - 80
restoredlg.ui

@@ -47,7 +47,7 @@
         </widget>
        </item>
        <item row="0" column="1">
-        <widget class="QComboBox" name="comboBox">
+        <widget class="QComboBox" name="dev_combobox">
          <property name="sizePolicy">
           <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
            <horstretch>0</horstretch>
@@ -84,10 +84,10 @@
         </widget>
        </item>
        <item row="1" column="1">
-        <widget class="QLineEdit" name="pathLineEdit"/>
+        <widget class="QLineEdit" name="dir_line_edit"/>
        </item>
        <item row="1" column="2">
-        <widget class="QToolButton" name="selectPathButton">
+        <widget class="QToolButton" name="select_path_button">
          <property name="text">
           <string>...</string>
          </property>
@@ -97,32 +97,7 @@
      </widget>
     </item>
     <item>
-     <spacer name="verticalSpacer">
-      <property name="orientation">
-       <enum>Qt::Vertical</enum>
-      </property>
-      <property name="sizeHint" stdset="0">
-       <size>
-        <width>20</width>
-        <height>215</height>
-       </size>
-      </property>
-     </spacer>
-    </item>
-   </layout>
-  </widget>
-  <widget class="QWizardPage" name="select_vms_page">
-   <layout class="QVBoxLayout" name="verticalLayout_4">
-    <item>
-     <widget class="QGroupBox" name="seletVMsGroupbox">
-      <property name="title">
-       <string>VMs to restore</string>
-      </property>
-      <layout class="QVBoxLayout" name="selectVMsLayout"/>
-     </widget>
-    </item>
-    <item>
-     <widget class="QGroupBox" name="groupBox">
+     <widget class="QGroupBox" name="options_groupbox">
       <property name="font">
        <font>
         <weight>50</weight>
@@ -134,22 +109,6 @@
       </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>
@@ -159,17 +118,14 @@
          </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>
+       <item row="0" column="1">
+        <widget class="QCheckBox" name="skip_dom0">
          <property name="text">
-          <string>skip conflicting</string>
+          <string>skip dom0</string>
          </property>
         </widget>
        </item>
-       <item row="1" column="0" colspan="2">
+       <item row="1" column="0">
         <widget class="QCheckBox" name="ignore_uname_mismatch">
          <property name="toolTip">
           <string>Ignore dom0 username mismatch while restoring homedir.</string>
@@ -182,6 +138,31 @@
       </layout>
      </widget>
     </item>
+    <item>
+     <spacer name="verticalSpacer">
+      <property name="orientation">
+       <enum>Qt::Vertical</enum>
+      </property>
+      <property name="sizeHint" stdset="0">
+       <size>
+        <width>20</width>
+        <height>215</height>
+       </size>
+      </property>
+     </spacer>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QWizardPage" name="select_vms_page">
+   <layout class="QVBoxLayout" name="verticalLayout_4">
+    <item>
+     <widget class="QGroupBox" name="select_vms_groupbox">
+      <property name="title">
+       <string>VMs to restore</string>
+      </property>
+      <layout class="QVBoxLayout" name="select_vms_layout"/>
+     </widget>
+    </item>
    </layout>
   </widget>
   <widget class="QWizardPage" name="confirm_page">
@@ -203,7 +184,7 @@
      </widget>
     </item>
     <item>
-     <widget class="QTextEdit" name="textEdit">
+     <widget class="QTextEdit" name="confirm_text_edit">
       <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;
 &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">
    <layout class="QVBoxLayout" name="verticalLayout_3">
     <item>
-     <widget class="QLabel" name="label_8">
-      <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>
+     <widget class="QTextEdit" name="commit_text_edit"/>
     </item>
    </layout>
   </widget>