def _on_dialog_show(self, widget):
     encoding = EncodingDialog.detect_textfile_encoding(self._dialog,
                                                        self._script_file)
     if encoding is None:
         self._error(self.STEP_LOADING_SUBMOD,
                     _('Could not determine encoding of Submod-script!'))
         return
     self._submod = Submod()
     self._load_script(encoding)
class ScriptRunDialog(object):
    STEP_LOADING_SUBMOD = 0
    STEP_LOADING_CUTLIST = 1
    STEP_LOADING_SUBTITLE = 2
    STEP_RUNNING_SUBMOD = 3
    STEP_SAVING_SUBTITLE = 4
    STEP_DONE = 5

    def __init__(self, parent, script_file):
        self._script_file = script_file
        self._submod = None
        self._cuts = None
        
        builder = Gtk.Builder()
        glade_file = Resources.find(path.join('data', 'gui', 'glade',
                                              'script_run_dialog.glade'))
        builder.add_from_file(glade_file)
        self._dialog = builder.get_object('script_run_dialog')
        self._dialog.set_transient_for(parent)
        builder.connect_signals(self)

        self._spin_loading_submod = builder.get_object('spin_loading_submod')
        self._img_loading_submod = builder.get_object('img_loading_submod')
        self._spin_loading_cutlist = builder.get_object('spin_loading_cutlist')
        self._img_loading_cutlist = builder.get_object('img_loading_cutlist')
        self._spin_loading_subtitle = builder.get_object(
                                                        'spin_loading_subtitle')
        self._img_loading_subtitle = builder.get_object('img_loading_subtitle')
        self._spin_running_submod = builder.get_object('spin_running_submod')
        self._img_running_submod = builder.get_object('img_running_submod')
        self._spin_saving_subtitle = builder.get_object('spin_saving_subtitle')
        self._img_saving_subtitle = builder.get_object('img_saving_subtitle')
        self._scroll_log = builder.get_object('scroll_log')
        self._txt_log = builder.get_object('txt_log')
        self._btn_close = builder.get_object('btn_close')
        
        self._step_icons = [
            self._spin_loading_submod, self._img_loading_submod,
            self._spin_loading_cutlist, self._img_loading_cutlist,
            self._spin_loading_subtitle, self._img_loading_subtitle,
            self._spin_running_submod, self._img_running_submod,
            self._spin_saving_subtitle, self._img_saving_subtitle
        ]
    
    def run(self):
        return self._dialog.run()

    def destroy_dialog(self):
        return self._dialog.destroy()

    def _on_dialog_show(self, widget):
        encoding = EncodingDialog.detect_textfile_encoding(self._dialog,
                                                           self._script_file)
        if encoding is None:
            self._error(self.STEP_LOADING_SUBMOD,
                        _('Could not determine encoding of Submod-script!'))
            return
        self._submod = Submod()
        self._load_script(encoding)
    
    @ThreadHelpers.run_in_thread
    def _load_script(self, encoding):
        """Try to load the Submod-script in a new thread.
        
        Then continue with the next step (load cutlist).
        """
        try:
            self._submod.load(self._script_file, encoding)
        except Exception as e:
            self._error(self.STEP_LOADING_SUBMOD, unicode(e))
            return
        self._open_cutlist()

    @GLibHelpers.idle_add
    def _open_cutlist(self):
        self._show_step_icons(self.STEP_LOADING_CUTLIST)
        if self._submod.script['timings-for'] == 'uncut':
            dialog = Gtk.MessageDialog(self._dialog, 0, 
                        Gtk.MessageType.QUESTION,
                        Gtk.ButtonsType.YES_NO,
                        _('Do you want to synchronize the subtitles for a cutli'
                          'st file?'))
            res = dialog.run()
            dialog.destroy()
            if res == Gtk.ResponseType.YES:
                filechooser = ExtFileChooserDialog(
                          self._dialog, _('Please choose a cutlist file'), True)
                folder = Settings().get(self, 'cuts_folder')
                if folder is not None:
                    filechooser.set_current_folder(folder)
                filter_subtitle = Gtk.FileFilter()
                filter_subtitle.set_name(_('Cutlist files')+' (*.cutlist)')
                filter_subtitle.add_pattern('*.cutlist')
                filechooser.add_filter(filter_subtitle)
                res = filechooser.run()
                file_ = filechooser.get_filename()
                filechooser.destroy_dialog()
                if res == Gtk.ResponseType.OK and path.isfile(file_):
                    dir_, filename = path.split(file_)
                    Settings().set(self, 'cuts_folder', dir_)
                    encoding = filechooser.encoding
                    if encoding is None:
                        encoding = EncodingDialog.detect_textfile_encoding(
                                                            self._dialog, file_)
                    if encoding is None:
                        self._error(self.STEP_LOADING_CUTLIST,
                                   _('Cutlist encoding could not be detected!'))
                        return
                    self._load_cutlist(file_, encoding)
                    # Since _load_cutlist will continue to the next step
                    # (detect subtitle encoding) we return here, s.b..
                    return
                else:
                    self._error(self.STEP_LOADING_CUTLIST,
                                           _('No cutlist selected! Cancelled!'))
                    return
        self._detect_subtitle_encoding()

    @ThreadHelpers.run_in_thread
    def _load_cutlist(self, file_, encoding):
        try:
            self._cuts = CutsFile.load_cutlist(file_, encoding)
        except Exception as e:
            self._error(self.STEP_LOADING_CUTLIST,
                       _('Failed to load cutlist file:\n{}!').format(e.args[0]))
            return
        self._detect_subtitle_encoding()

    @GLibHelpers.idle_add
    def _detect_subtitle_encoding(self):
        """Try to detect the encoding of the subtitle file if it's not
        set in the submod-script.
        
        This is done in the Gtk-thread because a dialog may be shown to
        select the proper encoding if it can not be detected
        automatically.
        
        Then continue with the next step (load subtitle and run Submod-
        script).
        """
        self._show_step_icons(self.STEP_LOADING_SUBTITLE)
        # Generate path for subtitle based on script-directory and
        # subtitle filename from the script.
        subtitle_filename = self._submod.script['subtitle']['filename']
        dir_, script_filename = path.split(self._script_file)
        subtitle_file = path.join(dir_, subtitle_filename)
        if not path.isfile(subtitle_file):
            self._error(self.STEP_LOADING_SUBTITLE,
                 _('Could not find subtitle file "{}"!').format(subtitle_file))
            return
        encoding = None
        if 'encoding' in self._submod.script['subtitle']:
            encoding = self._submod.script['subtitle']['encoding']
        if encoding is None:
            encoding = EncodingDialog.detect_textfile_encoding(self._dialog,
                                                               subtitle_file)
        if encoding is None:
            self._error(self.STEP_LOADING_SUBTITLE,
                           _('Could not determine encoding of subtitle file!'))
            return
        self._load_subtitle_run_script(subtitle_file, encoding)
        
    def _load_subtitle(self, subtitle_file, encoding):
        subtitle_list = SubtitleFile.load_srt(subtitle_file, encoding)
        self._show_step_icons(self.STEP_RUNNING_SUBMOD)
        return subtitle_list
    
    @ThreadHelpers.run_in_thread
    def _load_subtitle_run_script(self, subtitle_file, encoding):
        """Try to run the Submod-script in a new thread.
        """
        try:
            subtitle_loader = lambda f: self._load_subtitle(f, encoding)
            subtitle_list = self._submod.run(subtitle_file, subtitle_loader,
                                             self._cuts)
        except Exception as e:
            # Maybe the subtitle-checksum was wrong. Then an Exception
            # is raised before the subtitle was loaded. In that case
            # _load_subtitle was not called and thus the
            # STEP_RUNNING_SUBMOD-icons are not shown yet.
            # NOTE: _load_subtitle may raise an Exception, too.
            self._show_step_icons(self.STEP_RUNNING_SUBMOD)
            self._error(self.STEP_RUNNING_SUBMOD, unicode(e))
            return
        # Script has run, now save the new subtitle list.
        self._show_step_icons(self.STEP_SAVING_SUBTITLE)
        dir_, __ = path.split(self._script_file)
        # Generate name for new subtitle file based on the name of the
        # old subtitle file. '_submod' will be added before the file
        # extension. If the file already exists a new filename is
        # generated (by adding '.1', '.2' .. before the extension)
        # until a non existing filename is found.
        subtitle_filename = self._submod.script['subtitle']['filename']
        name_parts = subtitle_filename.rsplit('.', 1)
        name_base = name_parts[0] + '_submod'
        ext = '.'+name_parts[1] if len(name_parts)==2 else ''
        new_subtitle_file = path.join(dir_, name_base + ext)
        c = 0
        while path.isfile(new_subtitle_file):
            c += 1
            new_subtitle_file = path.join(dir_, name_base + '.' + str(c) + ext)
        try:
            SubtitleFile.save_srt(new_subtitle_file, subtitle_list)
        except Exception as e:
            self._error(self.STEP_SAVING_SUBTITLE, unicode(e))
            return
        self._show_step_icons(self.STEP_DONE)
        GLib.idle_add(self._allow_close)

    @GLibHelpers.idle_add
    def _show_step_icons(self, step):
        """Hides the spinner and shows the success-icon of the previous
        step and shows the spinner for the given step.
        """
        offset = (step-1)*2
        self._step_icons[offset].hide()
        self._step_icons[offset+1].show()
        if offset+2<len(self._step_icons):
            self._step_icons[offset+2].show()

    @GLibHelpers.idle_add
    def _error(self, step, text):
        """Hide the spinner and show the error icon for the given step
        and show the log-view containing the error text.
        """
        spin, image = self._step_icons[step*2], self._step_icons[step*2+1]
        spin.hide()
        image.set_from_icon_name('gtk-dialog-error', Gtk.IconSize.BUTTON)
        image.show()
        self._set_log(text)
        self._allow_close()

    def _set_log(self, text):
        self._txt_log.get_buffer().set_text(text.encode('utf-8'))
        self._scroll_log.show()

    def _allow_close(self):
        self._btn_close.set_sensitive(True)