예제 #1
0
    def edit_book(self, file_name, progress_frac, selected_text):
        import subprocess

        from calibre.ebooks.oeb.polish.main import SUPPORTED
        from calibre.utils.ipc.launch import exe_path, macos_edit_book_bundle_path
        try:
            path = set_book_path.pathtoebook
        except AttributeError:
            return error_dialog(self, _('Cannot edit book'), _(
                'No book is currently open'), show=True)
        fmt = path.rpartition('.')[-1].upper().replace('ORIGINAL_', '')
        if fmt not in SUPPORTED:
            return error_dialog(self, _('Cannot edit book'), _(
                'The book must be in the %s formats to edit.'
                '\n\nFirst convert the book to one of these formats.'
            ) % (_(' or ').join(SUPPORTED)), show=True)
        exe = 'ebook-edit'
        if ismacos:
            exe = os.path.join(macos_edit_book_bundle_path(), exe)
        else:
            exe = exe_path(exe)
        cmd = [exe]
        if selected_text:
            cmd += ['--select-text', selected_text]
        from calibre.gui2.tweak_book.widgets import BusyCursor
        with sanitize_env_vars():
            subprocess.Popen(cmd + [path, file_name])
            with BusyCursor():
                time.sleep(2)
예제 #2
0
def run(cmd):
    from calibre.gui2 import sanitize_env_vars
    with sanitize_env_vars():
        p = subprocess.Popen(list(map(encode_arg, cmd)), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout, stderr = p.communicate()
    ret = p.wait()
    return ret, decode_output(stdout), decode_output(stderr)
예제 #3
0
 def run_program(entry, path, parent):  # noqa
     import re
     cmdline = entry_to_cmdline(entry, path)
     flags = win32con.CREATE_DEFAULT_ERROR_MODE | win32con.CREATE_NEW_PROCESS_GROUP
     if re.match(r'"[^"]+?(.bat|.cmd|.com)"', cmdline, flags=re.I):
         flags |= win32con.CREATE_NO_WINDOW
         console = ' (console)'
     else:
         flags |= win32con.DETACHED_PROCESS
         console = ''
     print('Running Open With commandline%s:' % console,
           repr(entry['cmdline']), ' |==> ', repr(cmdline))
     try:
         with sanitize_env_vars():
             process_handle, thread_handle, process_id, thread_id = CreateProcess(
                 None, cmdline, None, None, False, flags, None, None,
                 STARTUPINFO())
         WaitForInputIdle(process_handle, 2000)
     except Exception as err:
         return error_dialog(
             parent,
             _('Failed to run'),
             _('Failed to run program, click "Show Details" for more information'
               ),
             det_msg='Command line: %r\n%s' % (cmdline, as_unicode(err)))
예제 #4
0
def run(cmd):
    from calibre.gui2 import sanitize_env_vars
    with sanitize_env_vars():
        p = subprocess.Popen(list(map(encode_arg, cmd)),
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
    stdout, stderr = p.communicate()
    ret = p.wait()
    return ret, decode_output(stdout), decode_output(stderr)
예제 #5
0
def kdialog_supports_desktopfile():
    ans = getattr(kdialog_supports_desktopfile, 'ans', None)
    if ans is None:
        from calibre.gui2 import sanitize_env_vars
        try:
            with sanitize_env_vars():
                raw = subprocess.check_output(['kdialog', '--help'])
        except (subprocess.CalledProcessError, FileNotFoundError, OSError):
            raw = b'--desktopfile'
        ans = kdialog_supports_desktopfile.ans = b'--desktopfile' in raw
    return ans
예제 #6
0
def run(cmd):
    from calibre.gui2 import sanitize_env_vars
    if DEBUG:
        try:
            print(cmd)
        except Exception:
            pass
    with sanitize_env_vars():
        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout, stderr = p.communicate()
    ret = p.wait()
    return ret, decode_output(stdout), decode_output(stderr)
예제 #7
0
def run(cmd):
    from calibre.gui2 import sanitize_env_vars
    ecmd = list(map(encode_arg, cmd))
    if DEBUG:
        try:
            print(ecmd)
        except Exception:
            pass
    with sanitize_env_vars():
        p = subprocess.Popen(ecmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout, stderr = p.communicate()
    ret = p.wait()
    return ret, decode_output(stdout), decode_output(stderr)
예제 #8
0
 def run_program(entry, path, parent):  # noqa
     cmdline = entry_to_cmdline(entry, path)
     print('Running Open With commandline:', repr(entry['cmdline']), ' |==> ', repr(cmdline))
     try:
         with sanitize_env_vars():
             process_handle, thread_handle, process_id, thread_id = CreateProcess(
                 None, cmdline, None, None, False, win32con.CREATE_DEFAULT_ERROR_MODE | win32con.CREATE_NEW_PROCESS_GROUP | win32con.DETACHED_PROCESS,
                 None, None, STARTUPINFO())
         WaitForInputIdle(process_handle, 2000)
     except Exception as err:
         return error_dialog(
             parent, _('Failed to run'), _(
             'Failed to run program, click "Show Details" for more information'),
             det_msg='Command line: %r\n%s' %(cmdline, as_unicode(err)))
예제 #9
0
 def run_program(entry, path, parent):  # noqa
     cmdline = entry_to_cmdline(entry, path)
     print('Running Open With commandline:', repr(entry['cmdline']), ' |==> ', repr(cmdline))
     try:
         with sanitize_env_vars():
             process_handle, thread_handle, process_id, thread_id = CreateProcess(
                 None, cmdline, None, None, False, win32con.CREATE_DEFAULT_ERROR_MODE | win32con.CREATE_NEW_PROCESS_GROUP | win32con.DETACHED_PROCESS,
                 None, None, STARTUPINFO())
         WaitForInputIdle(process_handle, 2000)
     except Exception as err:
         return error_dialog(
             parent, _('Failed to run'), _(
             'Failed to run program, click "Show Details" for more information'),
             det_msg='Command line: %r\n%s' %(cmdline, as_unicode(err)))
예제 #10
0
def run_program(entry, path, parent):
    import subprocess
    cmdline = entry_to_cmdline(entry, path)
    print('Running Open With commandline:', repr(cmdline))
    try:
        with sanitize_env_vars():
            process = subprocess.Popen(cmdline)
    except Exception as err:
        return error_dialog(
            parent, _('Failed to run'), _(
            'Failed to run program, click "Show Details" for more information'),
            det_msg='Command line: %r\n%s' %(cmdline, as_unicode(err)))
    t = Thread(name='WaitProgram', target=process.wait)
    t.daemon = True
    t.start()
예제 #11
0
def run_program(entry, path, parent):
    import subprocess
    cmdline = entry_to_cmdline(entry, path)
    print('Running Open With commandline:', repr(cmdline))
    try:
        with sanitize_env_vars():
            process = subprocess.Popen(cmdline)
    except Exception as err:
        return error_dialog(
            parent, _('Failed to run'), _(
            'Failed to run program, click "Show details" for more information'),
            det_msg='Command line: %r\n%s' %(cmdline, as_unicode(err)))
    t = Thread(name='WaitProgram', target=process.wait)
    t.daemon = True
    t.start()
예제 #12
0
 def run_program(entry, path, parent):  # noqa
     import re
     cmdline = entry_to_cmdline(entry, path)
     flags = subprocess.CREATE_DEFAULT_ERROR_MODE | subprocess.CREATE_NEW_PROCESS_GROUP
     if re.match(r'"[^"]+?(.bat|.cmd|.com)"', cmdline, flags=re.I):
         flags |= subprocess.CREATE_NO_WINDOW
         console = ' (console)'
     else:
         flags |= subprocess.DETACHED_PROCESS
         console = ''
     print('Running Open With commandline%s:' % console, repr(entry['cmdline']), ' |==> ', repr(cmdline))
     try:
         with sanitize_env_vars():
             winutil.run_cmdline(cmdline, flags, 2000)
     except Exception as err:
         return error_dialog(
             parent, _('Failed to run'), _(
             'Failed to run program, click "Show details" for more information'),
             det_msg='Command line: %r\n%s' %(cmdline, as_unicode(err)))
예제 #13
0
 def run_program(entry, path, parent):  # noqa
     import re
     cmdline = entry_to_cmdline(entry, path)
     flags = win32con.CREATE_DEFAULT_ERROR_MODE | win32con.CREATE_NEW_PROCESS_GROUP
     if re.match(r'"[^"]+?(.bat|.cmd|.com)"', cmdline, flags=re.I):
         flags |= win32con.CREATE_NO_WINDOW
         console = ' (console)'
     else:
         flags |= win32con.DETACHED_PROCESS
         console = ''
     print('Running Open With commandline%s:' % console, repr(entry['cmdline']), ' |==> ', repr(cmdline))
     try:
         with sanitize_env_vars():
             process_handle, thread_handle, process_id, thread_id = CreateProcess(
                 None, cmdline, None, None, False,  flags,
                 None, None, STARTUPINFO())
         WaitForInputIdle(process_handle, 2000)
     except Exception as err:
         return error_dialog(
             parent, _('Failed to run'), _(
             'Failed to run program, click "Show Details" for more information'),
             det_msg='Command line: %r\n%s' %(cmdline, as_unicode(err)))
예제 #14
0
def run_file_dialog(
        parent=None, title=None, initial_folder=None, filename=None, save_path=None,
        allow_multiple=False, only_dirs=False, confirm_overwrite=True, save_as=False, no_symlinks=False,
        file_types=()
):
    from calibre.gui2 import sanitize_env_vars
    with sanitize_env_vars():
        env = os.environ.copy()
    pipename = '\\\\.\\pipe\\%s' % uuid4()
    data = [serialize_string('PIPENAME', pipename)]
    parent = parent or None
    if parent is not None:
        data.append(serialize_hwnd(get_hwnd(parent)))
    if title:
        data.append(serialize_string('TITLE', title))
    if no_symlinks:
        data.append(serialize_binary('NO_SYMLINKS', no_symlinks))
    if save_as:
        data.append(serialize_binary('SAVE_AS', save_as))
        if confirm_overwrite:
            data.append(serialize_binary('CONFIRM_OVERWRITE', confirm_overwrite))
        if save_path is not None:
            save_path = process_path(save_path)
            if os.path.exists(save_path):
                data.append(serialize_string('SAVE_PATH', save_path))
            else:
                if not initial_folder:
                    initial_folder = select_initial_dir(save_path)
                if not filename:
                    filename = os.path.basename(save_path)
    else:
        if allow_multiple:
            data.append(serialize_binary('MULTISELECT', allow_multiple))
        if only_dirs:
            data.append(serialize_binary('ONLY_DIRS', only_dirs))
    if initial_folder is not None:
        initial_folder = process_path(initial_folder)
        if os.path.isdir(initial_folder):
            data.append(serialize_string('FOLDER', initial_folder))
    if filename:
        if isinstance(filename, bytes):
            filename = filename.decode(filesystem_encoding)
        data.append(serialize_string('FILENAME', filename))
    if only_dirs:
        file_types = ()  # file types not allowed for dir only dialogs
    elif not file_types:
        file_types = [(_('All files'), ('*',))]
    if file_types:
        data.append(serialize_file_types(file_types))
    loop = Loop()
    server = PipeServer(pipename)
    h = Helper(subprocess.Popen(
        [HELPER], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, env=env),
               data, loop.dialog_closed.emit)
    h.start()
    loop.exec_(QEventLoop.ExcludeUserInputEvents)
    def decode(x):
        x = x or b''
        try:
            x = x.decode('utf-8')
        except Exception:
            x = repr(x)
        return x

    if h.rc != 0:
        raise Exception('File dialog failed: ' + decode(h.stdoutdata) + ' ' + decode(h.stderrdata))
    server.join(2)
    if server.is_alive():
        raise Exception('Timed out waiting for read from pipe to complete')
    if server.err_msg:
        raise Exception(server.err_msg)
    if not server.data:
        return ()
    ans = tuple((os.path.abspath(x.decode('utf-8')) for x in server.data.split(b'\0') if x))
    return ans
예제 #15
0
def run_file_dialog(
        parent=None, title=None, initial_folder=None, filename=None, save_path=None,
        allow_multiple=False, only_dirs=False, confirm_overwrite=True, save_as=False, no_symlinks=False,
        file_types=(), default_ext=None
):
    from calibre.gui2 import sanitize_env_vars
    secret = os.urandom(32).replace(b'\0', b' ')
    pipename = '\\\\.\\pipe\\%s' % uuid4()
    data = [serialize_string('PIPENAME', pipename), serialize_secret(secret)]
    parent = parent or None
    if parent is not None:
        data.append(serialize_hwnd(get_hwnd(parent)))
    if title:
        data.append(serialize_string('TITLE', title))
    if no_symlinks:
        data.append(serialize_binary('NO_SYMLINKS', no_symlinks))
    if save_as:
        data.append(serialize_binary('SAVE_AS', save_as))
        if confirm_overwrite:
            data.append(serialize_binary('CONFIRM_OVERWRITE', confirm_overwrite))
        if save_path is not None:
            save_path = process_path(save_path)
            if os.path.exists(save_path):
                data.append(serialize_string('SAVE_PATH', save_path))
            else:
                if not initial_folder:
                    initial_folder = select_initial_dir(save_path)
                if not filename:
                    filename = os.path.basename(save_path)
    else:
        if allow_multiple:
            data.append(serialize_binary('MULTISELECT', allow_multiple))
        if only_dirs:
            data.append(serialize_binary('ONLY_DIRS', only_dirs))
    if initial_folder is not None:
        initial_folder = process_path(initial_folder)
        if os.path.isdir(initial_folder):
            data.append(serialize_string('FOLDER', initial_folder))
    if filename:
        if isinstance(filename, bytes):
            filename = filename.decode(filesystem_encoding)
        data.append(serialize_string('FILENAME', filename))
    if only_dirs:
        file_types = ()  # file types not allowed for dir only dialogs
    elif not file_types:
        file_types = [(_('All files'), ('*',))]
    if file_types:
        data.append(serialize_file_types(file_types))
    if default_ext:
        data.append(serialize_string('DEFAULT_EXTENSION', default_ext))
    loop = Loop()
    server = PipeServer(pipename)
    with sanitize_env_vars():
        h = Helper(subprocess.Popen(
            [HELPER], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE),
               data, loop.dialog_closed.emit)
    h.start()
    loop.exec_(QEventLoop.ExcludeUserInputEvents)

    def decode(x):
        x = x or b''
        try:
            x = x.decode('utf-8')
        except Exception:
            x = repr(x)
        return x

    def get_errors():
        return decode(h.stdoutdata) + ' ' + decode(h.stderrdata)
    from calibre import prints
    from calibre.constants import DEBUG
    if DEBUG:
        prints('stdout+stderr from file dialog helper:', type('')([h.stdoutdata, h.stderrdata]))

    if h.rc != 0:
        raise Exception('File dialog failed (return code %s): %s' % (h.rc, get_errors()))
    server.join(2)
    if server.is_alive():
        raise Exception('Timed out waiting for read from pipe to complete')
    if server.err_msg:
        raise Exception(server.err_msg)
    if not server.data:
        return ()
    parts = list(filter(None, server.data.split(b'\0')))
    if DEBUG:
        prints('piped data from file dialog helper:', type('')(parts))
    if len(parts) < 2:
        return ()
    if parts[0] != secret:
        raise Exception('File dialog failed, incorrect secret received: ' + get_errors())
    ans = tuple((os.path.abspath(x.decode('utf-8')) for x in parts[1:]))
    return ans
예제 #16
0
def run_file_dialog(parent=None,
                    title=None,
                    initial_folder=None,
                    filename=None,
                    save_path=None,
                    allow_multiple=False,
                    only_dirs=False,
                    confirm_overwrite=True,
                    save_as=False,
                    no_symlinks=False,
                    file_types=(),
                    default_ext=None,
                    app_uid=None):
    from calibre.gui2 import sanitize_env_vars
    secret = os.urandom(32).replace(b'\0', b' ')
    pipename = '\\\\.\\pipe\\%s' % uuid4()
    data = [serialize_string('PIPENAME', pipename), serialize_secret(secret)]
    parent = parent or None
    if parent is not None:
        data.append(serialize_hwnd(get_hwnd(parent)))
    if title:
        data.append(serialize_string('TITLE', title))
    if no_symlinks:
        data.append(serialize_binary('NO_SYMLINKS', no_symlinks))
    if save_as:
        data.append(serialize_binary('SAVE_AS', save_as))
        if confirm_overwrite:
            data.append(
                serialize_binary('CONFIRM_OVERWRITE', confirm_overwrite))
        if save_path is not None:
            save_path = process_path(save_path)
            if os.path.exists(save_path):
                data.append(serialize_string('SAVE_PATH', save_path))
            else:
                if not initial_folder:
                    initial_folder = select_initial_dir(save_path)
                if not filename:
                    filename = os.path.basename(save_path)
    else:
        if allow_multiple:
            data.append(serialize_binary('MULTISELECT', allow_multiple))
        if only_dirs:
            data.append(serialize_binary('ONLY_DIRS', only_dirs))
    if initial_folder is not None:
        initial_folder = process_path(initial_folder)
        if os.path.isdir(initial_folder):
            data.append(serialize_string('FOLDER', initial_folder))
    if filename:
        if isinstance(filename, bytes):
            filename = os.fsdecode(filename)
        data.append(serialize_string('FILENAME', filename))
    if only_dirs:
        file_types = ()  # file types not allowed for dir only dialogs
    elif not file_types:
        file_types = [(_('All files'), ('*', ))]
    if file_types:
        data.append(serialize_file_types(file_types))
    if default_ext:
        data.append(serialize_string('DEFAULT_EXTENSION', default_ext))
    app_uid = app_uid or current_app_uid
    if app_uid:
        data.append(serialize_string('APP_UID', app_uid))

    from qt.core import QEventLoop, Qt, pyqtSignal

    class Loop(QEventLoop):

        dialog_closed = pyqtSignal()

        def __init__(self):
            QEventLoop.__init__(self)
            self.dialog_closed.connect(self.exit,
                                       type=Qt.ConnectionType.QueuedConnection)

    loop = Loop()
    server = PipeServer(pipename)
    server.start()
    with sanitize_env_vars():
        h = Helper(
            subprocess.Popen([HELPER],
                             stdout=subprocess.PIPE,
                             stdin=subprocess.PIPE,
                             stderr=subprocess.PIPE), data,
            loop.dialog_closed.emit)
    h.start()
    loop.exec(QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents)

    def decode(x):
        x = x or b''
        try:
            x = x.decode('utf-8')
        except Exception:
            x = repr(x)
        return x

    def get_errors():
        return decode(h.stdoutdata) + ' ' + decode(h.stderrdata)

    from calibre import prints
    from calibre.constants import DEBUG
    if DEBUG:
        prints('stdout+stderr from file dialog helper:',
               str([h.stdoutdata, h.stderrdata]))

    if h.rc != 0:
        raise Exception(
            f'File dialog failed (return code {h.rc}): {get_errors()}')
    server.join(2)
    if server.is_alive():
        raise Exception('Timed out waiting for read from pipe to complete')
    if server.err_msg:
        raise Exception(server.err_msg)
    if not server.data:
        return ()
    parts = list(filter(None, server.data.split(b'\0')))
    if DEBUG:
        prints('piped data from file dialog helper:', str(parts))
    if len(parts) < 2:
        return ()
    if parts[0] != secret:
        raise Exception('File dialog failed, incorrect secret received: ' +
                        get_errors())

    from calibre_extensions.winutil import get_long_path_name

    def fix_path(x):
        u = os.path.abspath(x.decode('utf-8'))
        with suppress(Exception):
            try:
                return get_long_path_name(u)
            except FileNotFoundError:
                base, fn = os.path.split(u)
                return os.path.join(get_long_path_name(base), fn)
        return u

    ans = tuple(map(fix_path, parts[1:]))
    return ans
예제 #17
0
    def __init__(
        self, title=_('Choose Files'),
        filters=[],
        add_all_files_filter=True,
        parent=None,
        modal=True,
        name='',
        mode=QFileDialog.ExistingFiles,
        default_dir=u'~',
        no_save_dir=False,
        combine_file_and_saved_dir=False
    ):
        from calibre.gui2 import dynamic, sanitize_env_vars
        from calibre.gui2.ui import get_gui
        gui = get_gui()
        adapt_menubar = gui.bars_manager.adapt_menu_bar_for_dialog if gui is not None else Dummy()
        QObject.__init__(self)
        ftext = ''
        if filters:
            for filter in filters:
                text, extensions = filter
                extensions = ['*'+(i if i.startswith('.') else '.'+i) for i in
                        extensions]
                ftext += '%s (%s);;'%(text, ' '.join(extensions))
        if add_all_files_filter or not ftext:
            ftext += 'All files (*)'
        if ftext.endswith(';;'):
            ftext = ftext[:-2]

        self.dialog_name = dialog_name(name, title)
        self.selected_files = None
        self.fd = None

        if combine_file_and_saved_dir:
            bn = os.path.basename(default_dir)
            prev = dynamic.get(self.dialog_name,
                    os.path.expanduser(u'~'))
            if os.path.exists(prev):
                if os.path.isfile(prev):
                    prev = os.path.dirname(prev)
            else:
                prev = os.path.expanduser(u'~')
            initial_dir = os.path.join(prev, bn)
        elif no_save_dir:
            initial_dir = os.path.expanduser(default_dir)
        else:
            initial_dir = dynamic.get(self.dialog_name,
                    os.path.expanduser(default_dir))
        if not isinstance(initial_dir, string_or_bytes):
            initial_dir = os.path.expanduser(default_dir)
        if not initial_dir or (not os.path.exists(initial_dir) and not (
                mode == QFileDialog.AnyFile and (no_save_dir or combine_file_and_saved_dir))):
            initial_dir = select_initial_dir(initial_dir)
        self.selected_files = []
        use_native_dialog = 'CALIBRE_NO_NATIVE_FILEDIALOGS' not in os.environ
        with sanitize_env_vars():
            opts = QFileDialog.Option()
            if not use_native_dialog:
                opts |= QFileDialog.DontUseNativeDialog
            if mode == QFileDialog.AnyFile:
                with adapt_menubar:
                    f = QFileDialog.getSaveFileName(parent, title,
                        initial_dir, ftext, "", opts)
                if f and f[0]:
                    self.selected_files.append(f[0])
            elif mode == QFileDialog.ExistingFile:
                with adapt_menubar:
                    f = QFileDialog.getOpenFileName(parent, title,
                        initial_dir, ftext, "", opts)
                if f and f[0] and os.path.exists(f[0]):
                    self.selected_files.append(f[0])
            elif mode == QFileDialog.ExistingFiles:
                with adapt_menubar:
                    fs = QFileDialog.getOpenFileNames(parent, title, initial_dir,
                            ftext, "", opts)
                if fs and fs[0]:
                    for f in fs[0]:
                        f = unicode_type(f)
                        if not f:
                            continue
                        if not os.path.exists(f):
                            # QFileDialog for some reason quotes spaces
                            # on linux if there is more than one space in a row
                            f = unquote(f)
                        if f and os.path.exists(f):
                            self.selected_files.append(f)
            else:
                if mode == QFileDialog.Directory:
                    opts |= QFileDialog.ShowDirsOnly
                with adapt_menubar:
                    f = unicode_type(QFileDialog.getExistingDirectory(parent, title, initial_dir, opts))
                if os.path.exists(f):
                    self.selected_files.append(f)
        if self.selected_files:
            self.selected_files = [unicode_type(q) for q in self.selected_files]
            saved_loc = self.selected_files[0]
            if os.path.isfile(saved_loc):
                saved_loc = os.path.dirname(saved_loc)
            if not no_save_dir:
                dynamic[self.dialog_name] = saved_loc
        self.accepted = bool(self.selected_files)
예제 #18
0
    def __init__(self, title=_('Choose Files'),
                       filters=[],
                       add_all_files_filter=True,
                       parent=None,
                       modal=True,
                       name='',
                       mode=QFileDialog.ExistingFiles,
                       default_dir=u'~',
                       no_save_dir=False,
                       combine_file_and_saved_dir=False
                       ):
        from calibre.gui2 import dynamic, sanitize_env_vars
        QObject.__init__(self)
        ftext = ''
        if filters:
            for filter in filters:
                text, extensions = filter
                extensions = ['*'+(i if i.startswith('.') else '.'+i) for i in
                        extensions]
                ftext += '%s (%s);;'%(text, ' '.join(extensions))
        if add_all_files_filter or not ftext:
            ftext += 'All files (*)'
        if ftext.endswith(';;'):
            ftext = ftext[:-2]

        self.dialog_name = dialog_name(name, title)
        self.selected_files = None
        self.fd = None

        if combine_file_and_saved_dir:
            bn = os.path.basename(default_dir)
            prev = dynamic.get(self.dialog_name,
                    expanduser(u'~'))
            if os.path.exists(prev):
                if os.path.isfile(prev):
                    prev = os.path.dirname(prev)
            else:
                prev = expanduser(u'~')
            initial_dir = os.path.join(prev, bn)
        elif no_save_dir:
            initial_dir = expanduser(default_dir)
        else:
            initial_dir = dynamic.get(self.dialog_name,
                    expanduser(default_dir))
        if not isinstance(initial_dir, basestring):
            initial_dir = expanduser(default_dir)
        if not initial_dir or (not os.path.exists(initial_dir) and not (
                mode == QFileDialog.AnyFile and (no_save_dir or combine_file_and_saved_dir))):
            initial_dir = select_initial_dir(initial_dir)
        self.selected_files = []
        use_native_dialog = 'CALIBRE_NO_NATIVE_FILEDIALOGS' not in os.environ
        with sanitize_env_vars():
            opts = QFileDialog.Option()
            if not use_native_dialog:
                opts |= QFileDialog.DontUseNativeDialog
            if mode == QFileDialog.AnyFile:
                f = QFileDialog.getSaveFileName(parent, title,
                    initial_dir, ftext, "", opts)
                if f and f[0]:
                    self.selected_files.append(f[0])
            elif mode == QFileDialog.ExistingFile:
                f = QFileDialog.getOpenFileName(parent, title,
                    initial_dir, ftext, "", opts)
                if f and f[0] and os.path.exists(f[0]):
                    self.selected_files.append(f[0])
            elif mode == QFileDialog.ExistingFiles:
                fs = QFileDialog.getOpenFileNames(parent, title, initial_dir,
                        ftext, "", opts)
                if fs and fs[0]:
                    for f in fs[0]:
                        f = unicode(f)
                        if not f:
                            continue
                        if not os.path.exists(f):
                            # QFileDialog for some reason quotes spaces
                            # on linux if there is more than one space in a row
                            f = unquote(f)
                        if f and os.path.exists(f):
                            self.selected_files.append(f)
            else:
                if mode == QFileDialog.Directory:
                    opts |= QFileDialog.ShowDirsOnly
                f = unicode(QFileDialog.getExistingDirectory(parent, title, initial_dir, opts))
                if os.path.exists(f):
                    self.selected_files.append(f)
        if self.selected_files:
            self.selected_files = [unicode(q) for q in self.selected_files]
            saved_loc = self.selected_files[0]
            if os.path.isfile(saved_loc):
                saved_loc = os.path.dirname(saved_loc)
            if not no_save_dir:
                dynamic[self.dialog_name] = saved_loc
        self.accepted = bool(self.selected_files)
예제 #19
0
def run_file_dialog(parent=None,
                    title=None,
                    initial_folder=None,
                    filename=None,
                    save_path=None,
                    allow_multiple=False,
                    only_dirs=False,
                    confirm_overwrite=True,
                    save_as=False,
                    no_symlinks=False,
                    file_types=()):
    from calibre.gui2 import sanitize_env_vars
    with sanitize_env_vars():
        env = os.environ.copy()
    pipename = '\\\\.\\pipe\\%s' % uuid4()
    data = [serialize_string('PIPENAME', pipename)]
    parent = parent or None
    if parent is not None:
        data.append(serialize_hwnd(get_hwnd(parent)))
    if title:
        data.append(serialize_string('TITLE', title))
    if no_symlinks:
        data.append(serialize_binary('NO_SYMLINKS', no_symlinks))
    if save_as:
        data.append(serialize_binary('SAVE_AS', save_as))
        if confirm_overwrite:
            data.append(
                serialize_binary('CONFIRM_OVERWRITE', confirm_overwrite))
        if save_path is not None:
            save_path = process_path(save_path)
            if os.path.exists(save_path):
                data.append(serialize_string('SAVE_PATH', save_path))
            else:
                if not initial_folder:
                    initial_folder = select_initial_dir(save_path)
                if not filename:
                    filename = os.path.basename(save_path)
    else:
        if allow_multiple:
            data.append(serialize_binary('MULTISELECT', allow_multiple))
        if only_dirs:
            data.append(serialize_binary('ONLY_DIRS', only_dirs))
    if initial_folder is not None:
        initial_folder = process_path(initial_folder)
        if os.path.isdir(initial_folder):
            data.append(serialize_string('FOLDER', initial_folder))
    if filename:
        if isinstance(filename, bytes):
            filename = filename.decode(filesystem_encoding)
        data.append(serialize_string('FILENAME', filename))
    if only_dirs:
        file_types = ()  # file types not allowed for dir only dialogs
    elif not file_types:
        file_types = [(_('All files'), ('*', ))]
    if file_types:
        data.append(serialize_file_types(file_types))
    loop = Loop()
    server = PipeServer(pipename)
    h = Helper(
        subprocess.Popen([HELPER],
                         stdout=subprocess.PIPE,
                         stdin=subprocess.PIPE,
                         stderr=subprocess.PIPE,
                         env=env), data, loop.dialog_closed.emit)
    h.start()
    loop.exec_(QEventLoop.ExcludeUserInputEvents)

    def decode(x):
        x = x or b''
        try:
            x = x.decode('utf-8')
        except Exception:
            x = repr(x)
        return x

    if h.rc != 0:
        raise Exception('File dialog failed: ' + decode(h.stdoutdata) + ' ' +
                        decode(h.stderrdata))
    server.join(2)
    if server.is_alive():
        raise Exception('Timed out waiting for read from pipe to complete')
    if server.err_msg:
        raise Exception(server.err_msg)
    if not server.data:
        return ()
    ans = tuple((os.path.abspath(x.decode('utf-8'))
                 for x in server.data.split(b'\0') if x))
    return ans