#coding:utf-8

#!/usr/bin/python3
#
#  Copyright (c) 2007-2009 Canonical Ltd.
#
#  Author: Oliver Grawert <ogra@ubuntu.com>
#
#  Modifications 2013 from papoteur <papoteur@mageialinux-online.org>
#  and Geiger David <david.david@mageialinux-online.org>
#
#  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 St, Fifth Floor, Boston, MA 02110-1301, USA.

#  Requires python3-parted

# ensure we're using the latest build, if called from our build environment
import sys
import imp

sys.path.insert(0,'../../../build/swig/python3')
imp.reload(sys)
###########
# imports #
###########
import yui
import time

#log = yui.YUILog.instance()
#log.setLogFileName("isodumper.log")
#log.enableDebugLogging( True )

import os
import re
import gettext
from subprocess import call, Popen, PIPE
from pydbus import SystemBus
from gi.repository import GLib

import psutil

class NoUDisks2(Exception):
    pass


class UDisks2(object):

    BLOCK = 'org.freedesktop.UDisks2.Block'
    DRIVE = 'org.freedesktop.UDisks2.Drive'

    def __init__(self):
        self.bus = SystemBus()
        try:
            self.iface = self.bus.get('org.freedesktop.UDisks2')
        except :
            raise NoUDisks2()

    def find_devices(self):
        _udisks2_obj_manager = self.iface["org.freedesktop.DBus.ObjectManager"]
        objects=_udisks2_obj_manager.GetManagedObjects()
        re_drive = re.compile('(?P<path>.*?/drives/(?P<id>.*))')
        re_block = re.compile('(?P<path>.*?/block_devices/(?P<id>.*))')
        devs= [m.groupdict() for m in
                     [re_drive.match(path) for path in (objects.keys())]
                 if m]
        blocks = [m.groupdict() for m in
                     [re_block.match(path) for path in (objects.keys())]
                 if m]
        list=[]

        for block in blocks:
            if not block['path'][-1].isdigit():
                for dev in devs:
                    if dev['path'] == objects[block['path']][self.BLOCK]['Drive']:
                        dev_obj =objects[dev['path']][self.DRIVE]
                        if (dev_obj['ConnectionBus'] == 'usb' or dev_obj['ConnectionBus'] == 'sdio') and \
                            (dev_obj['Removable'] == 1 or dev_obj['MediaRemovable'] == 1 ):
                            item=[]
                            vend = dev_obj['Vendor']
                            if vend == "":
                                name = dev_obj['Model']
                            else:
                                name = vend + " "+ dev_obj['Model']
                            dev_name = block['path'].split('/')[-1]
                            path = '/dev/'+block['path'].split('/')[-1]
                            size = dev_obj['Size']
                            item.append(name)
                            item.append(path)
                            item.append(size)
                            list.append(item)
        return list

class Info(object):
    def __init__(self,title,richtext,text):
        self.title=title
        self.richtext=richtext
        self.text=text

       
class IsoDumper(object):

    RELEASE="v1.15"

    def get_devices(self):
        self.list=self.u.find_devices()
        while len(self.list)==0:
            if self.nodevDialog():
                self.list = self.u.find_devices()
            else:
                return False
                break
        self.devicelist.addItem("",False)
        if len(self.list)>0:
            for name, path, size in self.list:
              if size != 0 :
                self.devicelist.addItem(str(name+' ('+path.lstrip()+') ' + self.sizeof_fmt(size)),False)
            return True


    def update_list(self ):
        self.devicelist.deleteAllItems()
        self.get_devices()
        self.img_name = ""
        self.ima.setLabel(self.ChooseImage)
        self.backup_select.setLabel(self.ChooseImage)
        self.dialog.recalcLayout()
        self.restore()

    def device_selected(self):
        selitem = self.devicelist.selectedItem()
        if selitem != None:
            self.dev = selitem.label()
            for name, path, size in self.list:
                if self.dev.startswith(name):
                    self.deviceSize=size
                    self.device_name=name.rstrip().replace(' ', '')
                    self.logger(_('Target Device: ')+ self.dev)
                    self.formatbt.setEnabled()
                    self.ima.setEnabled()
                    self.backup_select.setEnabled()
                    break

    def sizeof_fmt(self, num):
        #I18N these are units for files size
        for unit in [_('B'),_('KiB'),_('MiB'),_('GiB'),_('TiB')]:
            if abs(num) < 1024.0:
                return "%3.3f %s" % (num, unit)
            num /= 1024.0
        return "%.1f %s" % (num, _('TiB'))

    def backup_choosed(self):
            # Add .img if not specified
            if not self.backup_img_name.lower().endswith('.img'):
                self.backup_img_name=self.backup_img_name+".img"
            head, tail = os.path.split(self.backup_img_name)
            self.backup_dest=self.backup_img_name
            self.backup_select.setLabel(tail)
            self.dialog.recalcLayout()
            self.backupbt.setEnabled()

    def do_format(self,format_type,name):
        target = self.dev.split('(')[1].split(')')[0]
        info = Info(_("Formatting confirmation"),True,self.warning)
        if self.ask_YesOrNo(info):
            rc=self.raw_format(target, format_type, name)
            self.operation=False
            if rc == 0:
                message = _('The device was formatted successfully.')
                self.logger(message)
                self.success()
            elif rc == 5:
                message = _("An error occurred while creating a partition.")
                self.logger(message)
                self.emergency(message)
            elif rc == 127:
                message = _('Authentication error.')
                self.logger(message)
                self.emergency(message)
            else:
                message = _('An error occurred.')
                self.emergency(message)

    def restore(self):
        self.backup_select.setDisabled()
        self.backupbt.setDisabled()
        self.formatbt.setDisabled()
        self.ima.setDisabled()
        self.writebt.setDisabled()
        self.devicelist.setEnabled()
        self.progress.setLabel("")
        self.progress.setValue(0)
        self.progress.setDisabled()
        self.refreshbt.setEnabled()
        self.persistencecb.setDisabled()

    def onProgress(self, frac):
        self.logger(_('Wrote: {}% '.format(frac)))
        self.progress.setValue(frac)
        self.dialog.pollEvent()
        
    def raw_format(self, usb_path, fstype, label):
        self.operation=True
        if os.geteuid() > 0:
            launcher='pkexec'
            self.process = Popen([launcher,'/usr/bin/python3', '-u', '/usr/lib/isodumper/raw_format.py','-d',usb_path,'-f',fstype, '-l', label, '-u', str(os.geteuid()), '-g', str(os.getgid())], shell=False, stdout=PIPE, preexec_fn=os.setsid)
        else:
            self.process = Popen(['/usr/bin/python3', '-u', '/usr/lib/isodumper/raw_format.py','-d',usb_path,'-f',fstype, '-l', label, '-u', str(os.geteuid()), '-g', str(os.getgid())], shell=False, stdout=PIPE, preexec_fn=os.setsid)
        working=True
        while working:
            time.sleep(0.5)
            self.process.poll()
            rc=self.process.returncode
            if rc is None:
                working=True
            else:
                self.process = None
                working= False
        return rc

    def backup_go(self):
        dest = self.backup_img_name
        if os.path.exists(dest):
            info = Info(_("Backup confirmation"),True,_("Do you want to overwrite the file?"))
            if not(self.ask_YesOrNo(info)):
                self.returncode = 1
                return True
        st = os.statvfs(os.path.dirname(dest))
        free = st.f_bavail * st.f_frsize
        if free<self.deviceSize :
            sizeM=str(self.deviceSize/(1024*1024))
            message=_("The destination directory is too small to receive the backup (%s Mb needed)")%(sizeM)
            self.logger(message)
            self.emergency(message)
        else:
            self.returncode=0
            source = self.dev.split('(')[1].split(')')[0]
            self.logger(_('Backup to:')+' '+dest)
            bus = SystemBus()
            iface = bus.get("org.mageia.Magiback","Isodumper")
            #Writing step
            iface.do_write(source, dest, self.deviceSize)
            progress = iface.progress
            while not iface.done :
                progress = iface.progress
                self.progress.setValue(progress)
                self.dialog.pollEvent()
                time.sleep(.2)
            success, message = iface.end()
            if success:
                self.logger(_('{source} successfully written to {target}').format( source=source.split('/')[-1], target=dest))
                self.progress.setEnabled()
                self.progress.setValue(100)
                self.dialog.pollEvent()
                self.logger(message)
                self.success()
            else:
                self.emergency(message)

    def do_write(self):
        self.writebt.setDisabled()
        self.devicelist.setDisabled()
        self.formatbt.setDisabled()
        self.backupbt.setDisabled()
        self.backup_select.setDisabled()
        self.progress.setEnabled()
        source = self.img_name
        target = self.dev.split('(')[1].split(')')[0]
#        self.logger(_('Image: ')+source)
#        self.logger(_('Target Device: ')+self.dev)
        b = os.path.getsize(source)
        if b > (self.deviceSize):
            message = _('The device is too small to contain the ISO file.')
            self.logger(message)
            self.emergency(message)
        else:
            info = Info(_("Writing confirmation"),True,self.warning)
            if self.ask_YesOrNo(info):
                if self.deviceSize> 1024*1024*1024*32 :
                    info = Info(_("Warning"),True,_('The device is bigger than 32 Gbytes. Are you sure you want use it?'))
                    if self.ask_YesOrNo(info):
                        pass
                    else:
                        return
                self.ima.setDisabled()
                self.writebt.setDisabled()
                self.progress.setLabel(_('Writing {source} to {target}').format(source=source.split('/')[-1],target=target.split('/')[-1]))
                self.logger(_('Executing copy from ')+source+_(' to ')+target)
                bus = SystemBus()
                iface = bus.get("org.mageia.Magiback","Isodumper")
                success, message = iface.do_unmount(target)
                if success:
                    #Writing step
                    #Dump mode
                    iface.do_write(source, target, b)
                    iface.get_sum(source)
                    progress = iface.progress
                    while not iface.done :
                        progress = iface.progress
                        self.progress.setValue(progress)
                        self.dialog.pollEvent()
                        time.sleep(.5)
                    success, message = iface.end()
                    if success:
                        self.logger(_('Image {source} successfully written to {target}').format( source=source.split('/')[-1], target=target))
                        self.logger(_('Bytes written: ')+str(b))
                        self.progress.setLabel(_('Checking ')+target.split('/')[-1])
                        self.progress.setValue(0) 
                        self.dialog.pollEvent()    
                        # Checking
                        iface.check_write(target, source)
                        progress = iface.progress
                        while progress < 100 :
                            progress = iface.progress
                            self.progress.setValue(progress)
                            self.dialog.pollEvent()
                            time.sleep(.5)
                        success, message = iface.end()
                        self.progress.setEnabled()
                        self.progress.setValue(100)
                        self.dialog.pollEvent()
                        self.logger(message)
                        # Add persistent partition if asked
                        if self.persistencecb.value():
                            self.logger(_("Adding persistent partition"))
                            iface.do_persistence(target,"mgalive-persist")
                            self.logger(_("Added persistent partition"))
                        self.success()
                    else:
                        self.emergency(message)
                else:
                    self.emergency(message)
                    self.restore()
            else:
                self.restore()

    def success(self):
        self.operation=False
        self.final_unsensitive()
        info = Info(_("Success"),True,_("The operation completed successfully.\n\
 You are free to unplug it now, a logfile \n\
(/home/-user- or /root)/.isodumper/isodumper.log will be saved when\n\
 you close the application."))
        if self.ask_OK(info) :
           return


    def confirm_close(self, *args):
        if self.operation==False:    # no writing , backup nor format running
            self.close()
        else:   # writing , backup or format running
            info = Info(_("Warning"),True,_("Writing is in progress. Exiting during writing \n\
            will make the device or the backup unusable.\n\
            Are you sure you want to quit during writing?"))
            if self.ask_YesOrNo(info) :
                return True
            else:
                return False

    def emergency(self,message):
        self.operation=False
        self.returncode=1
        self.final_unsensitive()
        info = Info(_("Error"),True,message)
        self.ask_OK(info)

    def final_unsensitive(self):
        self.ima.setDisabled()
        self.devicelist.setDisabled()
        self.writebt.setDisabled()
        self.progress.setDisabled()
        self.backup_select.setDisabled()
        self.persistencecb.setDisabled()

    def wip_unsensitive(self):
        self.ima.setDisabled()
        self.devicelist.setDisabled()
        self.writebt.setDisabled()
        self.backup_select.setDisabled()
        self.backupbt.setDisabled()
        self.refreshbt.setDisabled()
        self.persistencecb.setDisabled()
		
    def close(self):
        self.write_logfile()
        self.dialog.destroy()
        self.dialog = None

    def write_logfile(self):
        logpath = os.path.join(os.path.expanduser('~'),'.isodumper')
        if not(os.path.isdir(logpath)):
                os.mkdir(logpath)
        logfile=open(logpath+'/isodumper.log',"w", encoding="utf-8")
        logfile.write(self.logview.logText())
        logfile.close()

        print((self.logview.logText()))

    def logger(self, text):
        self.logview.appendLines(text+"\n")

    def activate_devicelist(self):
        self.devicelist.setEnabled()
        self.logger(_('Image ')+": "+ self.img_name)
#        self.chooser.set_tooltip_text(self.img_name)

    def help_dialog(self):
        info = Info(_("IsoDumper"),True,_("Mageia IsoDumper<BR />\
----------------<BR />\
This GUI program is primarily for safely writing a bootable ISO image to a USB flash drive, \
an operation devious & potentially hazardous when done by hand. As a bonus, it can also back up the\
entire previous<BR />contents of the flash drive onto the hard disc, and restore the flash drive \
to its previous state subsequently.<BR />\
It gives also a feature for formatting the USB device.<BR />\
<BR />\
IsoDumper can be launched either from the menus, or a user or root console with the command 'isodumper'.<BR />\
For normal users, the root password is solicited; this is necessary for the program's operation. <BR />\
The flash drive can be inserted beforehand or once the program is started. In the latter case, a \
dialogue will say that there is no flash drive inserted, and allow a 'retry' to find it once it is. <BR />\
(You may have to close any automatically opened File Manager window).<BR />\
<BR />\
The fields of the main window are as follows:<BR />\
- Device to work on: the device of the USB flash drive, a drop-down list to choose from.<BR />\
- Write Image: to choose the source ISO image *.iso (or flash drive backup file *.img) to write out.<BR />\
- Write to device: This button launches the operation - with a prior warning dialogue. <BR />\
The operation is shown in the progress bar beneath.<BR />\
- Backup to: define the name and placement of the backup image file. The current flash drive \
will be backed up to a disc file. Note that the entire flash drive is preserved, regardless of its \
actual contents; ensure that you have the necessary free disc space (the same size as the USB device). \
This backup file can be used later to restore the flash drive by selecting it as the source *.img file to write out.<BR />\
- Backup the device: launch the backup operation.<BR />\
- Format the device:  create an unique partition on the entire volume in the specified format in FAT, \
NTFS or ext. You can specify a volume name and the format in a new dialog box.<BR />"))
        if self.ask_OK(info) :
           return

    def __init__(self):
        APP="isodumper"
        DIR="/usr/share/locale"
        # Call translation catalog
        gettext.install(APP, localedir=DIR, names=('ngettext',))

        #Check that there is no other instance running
        current_pid = psutil.Process().pid
        for pid in psutil.pids():
            p = psutil.Process(pid)
            if p.name() == "isodumper" and p.pid != current_pid :
                info = Info(_("Error"),True,_("There is another instance of Isodumper already running."))
                self.ask_OK(info)
                yui.YUILoader.deleteUI()
                exit()


        #TODO Read log level from command line
 
        # define size of the selected device
        self.deviceSize=0

        # Operation running
        self.operation=False
        
        self.ChooseImage = _("Choose an image")
        self.warning = _("Warning\nThis will destroy all data on the target device,\n\
        are you sure you want to proceed?\n\
        If you say ok here, please <b>do not unplug</b>\
        the device during the following operation.")
        """
        Init/Constructor for the 'widgets'
        """
        yui.YUI.app().setApplicationTitle(_("IsoDumper")+" "+self.RELEASE)
        yui.YUI.app().setApplicationIcon("/usr/share/icons/isodumper.png")
        self.atelier = yui.YUI.widgetFactory()
        self.dialog = self.atelier.createPopupDialog()
        # create the main gui
        # +---+-----------------+
        # +   banner            +
        # +---+-----------------+
        # |  devicelist         |
        # +---+-----+------+----+
        # + L | ima | writebt |
        # +---+-----+------+----+
        # + L | backup_select | backupbt |
        # +---+-----+------+----+
        # + F       | formatbt  |
        # +----------------+----+
        # | progress            |
        # +---------------------+
        # | report              |
        # +---------------------+
        # | refreshbt | aboutbt  | helpbt | quitbt  |
        # +---------------------+
        self.ancrage = self.atelier.createReplacePoint(self.dialog)
        self.box = self.atelier.createVBox(self.ancrage)
        self.bannerbox = self.atelier.createHBox(self.box)
        self.banner=self.atelier.createImage(self.bannerbox,"/usr/share/isodumper/header.svg")
        self.devicebox = self.atelier.createHBox(self.box)
        self.devicelist=self.atelier.createComboBox(self.devicebox,_("Device to work on:"),False)
        self.devicelist.setNotify()
        self.devicelist.setStretchable(0,True)
        self.writebox = self.atelier.createHBox(self.box)
        self.atelier.createLabel(self.writebox,_("Write Image:"))
        #   add file picker for image file
        self.ima=self.atelier.createPushButton(self.writebox,self.ChooseImage)
        self.ima.setStretchable(0,True)
        self.ima.setDisabled()
        self.atelier.createHStretch(self.writebox)
        self.writebt = self.atelier.createPushButton(self.writebox, _("&Write to device" ))
        self.writebt.setDisabled()
        self.persistencebox = self.atelier.createHBox(self.box)
        self.persistencecb = self.atelier.createCheckBox(self.persistencebox, _("Add a persistent partition in the remaining space"))
        self.persistencecb.setDisabled()
        self.backupbox = self.atelier.createHBox(self.box)
        self.atelier.createLabel(self.backupbox,_("Backup to:"))
        #   add file picker for backup file name
        self.backup_select=self.atelier.createPushButton(self.backupbox,self.ChooseImage)
        self.backup_select.setStretchable(0,True)
        self.backup_select.setDisabled()
        self.atelier.createHStretch(self.backupbox)
        self.backupbt = self.atelier.createPushButton(self.backupbox, _("Backup the device" ))
        self.backupbt.setDisabled()
        self.formatbox = self.atelier.createHBox(self.box)
        self.atelier.createLabel(self.formatbox,_("Format the device in FAT, NTFS or ext:"))
        self.atelier.createHStretch(self.formatbox)
        self.formatbt = self.atelier.createPushButton(self.formatbox, _("Format the device" ))
        self.formatbt.setDisabled()
        self.progressbox = self.atelier.createHBox(self.box)
        self.progress = self.atelier.createProgressBar(self.progressbox,_("Progress"),100)
        self.progress.setStretchable(0,True)
        self.reportbox = self.atelier.createHBox(self.box)
        self.reportbox.setWeight(1,30)
        self.logview = self.atelier.createLogView(self.reportbox,_("Report"), 10)
        self.logview.setStretchable(0,True)
        self.buttonsbox = self.atelier.createHBox(self.box)
        self.refreshbt = self.atelier.createPushButton(self.devicebox, _("Refresh" ))
        self.refreshbt.setStretchable(0,True)
        self.aboutbt = self.atelier.createPushButton(self.buttonsbox, _("About" ))
        self.aboutbt.setStretchable(0,True)
        self.helpbt = self.atelier.createPushButton(self.buttonsbox, _("Help" ))
        self.helpbt.setStretchable(0,True)
        self.quitbt = self.atelier.createPushButton(self.buttonsbox, _("Quit" ))
        self.quitbt.setStretchable(0,True)
        self.u = None
        try:
            self.u = UDisks2()
        except :
           message = _('UDisks2 is not available on your system')
           self.logger(message)
           self.emergency(message)
        if not self.get_devices():
            self.dialog.destroy()
            yui.YUILoader.deleteUI()
            exit()
        self.device_selected()
        self.dialog.recalcLayout()
        self.ancrage.showChild()

    def ask_format(self):
        atelier =  yui.YUI.widgetFactory()       
        dialog = atelier.createPopupDialog()
#        dialog.setTitle(_("Choose format"))
        vb=atelier.createVBox(dialog)
        label = atelier.createInputField(vb,_("Label for the device:"))
        cr = atelier.createRadioButtonGroup(vb)
        vb_c = atelier.createVBox(cr)
        vb_c1 = atelier.createHBox(vb_c)
        format_fat = atelier.createRadioButton(atelier.createLeft(vb_c1),_("FAT 32 (Windows)"))
        vb_c2 = atelier.createHBox(vb_c)
        format_ntfs = atelier.createRadioButton(atelier.createLeft(vb_c2),_("NTFS (Windows)"))
        vb_c3 = atelier.createHBox(vb_c)
        format_ext = atelier.createRadioButton(atelier.createLeft(vb_c3),_("ext4 (Linux)"))
        bb = atelier.createHBox(vb)
        executebt = atelier.createPushButton(bb,_("Execute"))
        cancelbt = atelier.createPushButton(bb,_("Cancel"))
        dialog.open()
        returncode = True
        while True:
            event = dialog.waitForEvent()
            if event.eventType() == yui.YEvent.CancelEvent:
                returncode = False
                break
            if event.widget() == executebt:
                if format_fat.value():
                    format_type = 'fat32'
                    format_label = label.value().upper()[:11]
                    break
                if format_ntfs.value():
                    format_type = 'ntfs'
                    format_label = label.value()[:32]
                    break
                if format_ext.value():
                    format_type = 'ext4'
                    format_label = label.value()
                    break
            if event.widget() == cancelbt:
                returncode = False
                break
        dialog.destroy()
        if returncode:
            return True,format_type,format_label
        else:
            return False," "," "
        

    def ask_OK(self, info):
        yui.YUI.widgetFactory
        mgafactory = yui.YMGAWidgetFactory.getYMGAWidgetFactory(yui.YExternalWidgets.externalWidgetFactory("mga"))
        dlg = mgafactory.createDialogBox(yui.YMGAMessageBox.B_ONE)
        dlg.setTitle(info.title)
        dlg.setText(info.text, info.richtext)
        dlg.setButtonLabel(_("OK"), yui.YMGAMessageBox.B_ONE)
        dlg.setMinSize(60, 10);
        return dlg.show() == yui.YMGAMessageBox.B_ONE

    def ask_YesOrNo(self, info):
        yui.YUI.widgetFactory
        mgafactory = yui.YMGAWidgetFactory.getYMGAWidgetFactory(yui.YExternalWidgets.externalWidgetFactory("mga"))
        dlg = mgafactory.createDialogBox(yui.YMGAMessageBox.B_TWO)
        dlg.setTitle(info.title)
        dlg.setText(info.text, info.richtext)
        dlg.setButtonLabel(_("Yes"), yui.YMGAMessageBox.B_ONE)
        dlg.setButtonLabel(_("No"),  yui.YMGAMessageBox.B_TWO)
        dlg.setMinSize(60, 8);
        return dlg.show() == yui.YMGAMessageBox.B_ONE

    def aboutDialog(self):
        yui.YUI.widgetFactory;
        mgafactory = yui.YMGAWidgetFactory.getYMGAWidgetFactory(yui.YExternalWidgets.externalWidgetFactory("mga"))
        dlg = mgafactory.createAboutDialog("Isodumper", self.RELEASE, "GPLv2",
                                        _("Oliver Grawert<BR />Papoteur<BR />Pictures : Timothée Giet"), _("A tool for writing ISO images to  a device")+"<BR />http://gitweb.mageia.org/software/isodumper", "")
        dlg.show();
        
    def nodevDialog(self):
        yui.YUI.widgetFactory
        mgafactory = yui.YMGAWidgetFactory.getYMGAWidgetFactory(yui.YExternalWidgets.externalWidgetFactory("mga"))
        dlg = mgafactory.createDialogBox(yui.YMGAMessageBox.B_TWO)
        dlg.setTitle("IsoDumper")
        dlg.setText(_("Warning\nNo target devices were found.\nYou need to plug in a USB Key to which the image can be written."))
        dlg.setButtonLabel(_("Refresh"), yui.YMGAMessageBox.B_ONE)
        dlg.setButtonLabel(_("Cancel"),  yui.YMGAMessageBox.B_TWO)
        dlg.setMinSize(60, 8);
        return dlg.show() == yui.YMGAMessageBox.B_ONE

    def handleevent(self):
        self.traitement=None
        while True:
            event = self.dialog.waitForEvent()
            if event.eventType() == yui.YEvent.CancelEvent:
                self.close()
                break
            if event.widget() == self.quitbt:
                self.close()
                break
            if event.widget() == self.ima:
                    self.img_name=yui.YUI.app().askForExistingFile("","*.iso *.img",self.ChooseImage)
                    if self.img_name != "" :
                        self.ima.setLabel(os.path.basename(self.img_name))
                        self.dialog.recalcLayout()
                        self.writebt.setEnabled()
                        self.activate_devicelist()
                        self.persistencecb.setEnabled()
            if event.widget() == self.writebt:
                    self.wip_unsensitive()
                    self.do_write()
                    self.restore()
            if event.widget() == self.backupbt:
                self.wip_unsensitive()
                self.backup_go()
                self.restore()
            if event.widget() == self.backup_select:
                self.backup_img_name=yui.YUI.app().askForSaveFileName("","*.img",_("Backup to:"))
                if self.backup_img_name != '':
                        self.backup_choosed()
            if event.widget() == self.formatbt:
                    code,format_type,name = self.ask_format()
                    if code:
                        self.do_format(format_type,name)
                        self.restore()
            if event.widget() == self.devicelist:
                self.device_selected()
            try:
                if event.widget() == self.refreshbt:
                    self.update_list()
            except:
                pass
            try:
                if event.widget() == self.helpbt:
                    self.help_dialog()
            except:
                pass
            try:
                if event.widget() == self.quitbt:
                    self.confirm_close()
            except:
                pass
            if event.widget() == self.aboutbt:
                self.aboutDialog()

    def run(self):
        try:
            self.handleevent()
        except Exception as e:
            print(str(e))
            yui.YDialog.deleteAllDialogs()
      

if __name__ == "__main__":
    app = IsoDumper()
    app.run()
    # next line seems to be a workaround to prevent the qt-app from crashing
    # see https://github.com/libyui/libyui-qt/issues/41
    yui.YUILoader.deleteUI()