Allow directories to be entered as destination

The filename will then default to 'page title.mht'
This commit is contained in:
Daniel 2015-10-19 20:08:37 +02:00
parent ae8a9b8798
commit a780325a3a
2 changed files with 63 additions and 41 deletions

View File

@ -49,7 +49,7 @@ ModelRole = usertypes.enum('ModelRole', ['item'], start=Qt.UserRole,
RetryInfo = collections.namedtuple('RetryInfo', ['request', 'manager']) RetryInfo = collections.namedtuple('RetryInfo', ['request', 'manager'])
# Remember the last used directory # Remember the last used directory
_last_used_directory = None last_used_directory = None
# All REFRESH_INTERVAL milliseconds, speeds will be recalculated and downloads # All REFRESH_INTERVAL milliseconds, speeds will be recalculated and downloads
@ -57,13 +57,13 @@ _last_used_directory = None
REFRESH_INTERVAL = 500 REFRESH_INTERVAL = 500
def _download_dir(): def download_dir():
"""Get the download directory to use.""" """Get the download directory to use."""
directory = config.get('storage', 'download-directory') directory = config.get('storage', 'download-directory')
remember_dir = config.get('storage', 'remember-download-directory') remember_dir = config.get('storage', 'remember-download-directory')
if remember_dir and _last_used_directory is not None: if remember_dir and last_used_directory is not None:
return _last_used_directory return last_used_directory
elif directory is None: elif directory is None:
return standarddir.download() return standarddir.download()
else: else:
@ -79,15 +79,36 @@ def path_suggestion(filename):
suggestion = config.get('completion', 'download-path-suggestion') suggestion = config.get('completion', 'download-path-suggestion')
if suggestion == 'path': if suggestion == 'path':
# add trailing '/' if not present # add trailing '/' if not present
return os.path.join(_download_dir(), '') return os.path.join(download_dir(), '')
elif suggestion == 'filename': elif suggestion == 'filename':
return filename return filename
elif suggestion == 'both': elif suggestion == 'both':
return os.path.join(_download_dir(), filename) return os.path.join(download_dir(), filename)
else: else:
raise ValueError("Invalid suggestion value {}!".format(suggestion)) raise ValueError("Invalid suggestion value {}!".format(suggestion))
def create_full_filename(basename, filename):
"""Create a full filename based on the given basename and filename.
Args:
basename: The basename to use if filename is a directory.
filename: The path to a folder or file where you want to save.
Return:
The full absolute path, or None if filename creation was not possible.
"""
if os.path.isabs(filename) and os.path.isdir(filename):
# We got an absolute directory from the user, so we save it under
# the default filename in that directory.
return os.path.join(filename, basename)
elif os.path.isabs(filename):
# We got an absolute filename from the user, so we save it under
# that filename.
return filename
return None
class DownloadItemStats(QObject): class DownloadItemStats(QObject):
"""Statistics (bytes done, total bytes, time, etc.) about a download. """Statistics (bytes done, total bytes, time, etc.) about a download.
@ -447,7 +468,7 @@ class DownloadItem(QObject):
filename: The full filename to save the download to. filename: The full filename to save the download to.
None: special value to stop the download. None: special value to stop the download.
""" """
global _last_used_directory global last_used_directory
if self.fileobj is not None: if self.fileobj is not None:
raise ValueError("fileobj was already set! filename: {}, " raise ValueError("fileobj was already set! filename: {}, "
"existing: {}, fileobj {}".format( "existing: {}, fileobj {}".format(
@ -457,13 +478,16 @@ class DownloadItem(QObject):
# See https://github.com/The-Compiler/qutebrowser/issues/427 # See https://github.com/The-Compiler/qutebrowser/issues/427
encoding = sys.getfilesystemencoding() encoding = sys.getfilesystemencoding()
filename = utils.force_encoding(filename, encoding) filename = utils.force_encoding(filename, encoding)
if not self._create_full_filename(filename): self._filename = create_full_filename(self.basename, filename)
if self._filename is None:
# We only got a filename (without directory) or a relative path # We only got a filename (without directory) or a relative path
# from the user, so we append that to the default directory and # from the user, so we append that to the default directory and
# try again. # try again.
self._create_full_filename(os.path.join(_download_dir(), filename)) self._filename = create_full_filename(
self.basename, os.path.join(download_dir(), filename))
_last_used_directory = os.path.dirname(self._filename) self.basename = os.path.basename(self._filename)
last_used_directory = os.path.dirname(self._filename)
log.downloads.debug("Setting filename to {}".format(filename)) log.downloads.debug("Setting filename to {}".format(filename))
if os.path.isfile(self._filename): if os.path.isfile(self._filename):
@ -480,25 +504,6 @@ class DownloadItem(QObject):
else: else:
self._create_fileobj() self._create_fileobj()
def _create_full_filename(self, filename):
"""Try to create the full filename.
Return:
True if the full filename was created, False otherwise.
"""
if os.path.isabs(filename) and os.path.isdir(filename):
# We got an absolute directory from the user, so we save it under
# the default filename in that directory.
self._filename = os.path.join(filename, self.basename)
return True
elif os.path.isabs(filename):
# We got an absolute filename from the user, so we save it under
# that filename.
self._filename = filename
self.basename = os.path.basename(self._filename)
return True
return False
def set_fileobj(self, fileobj): def set_fileobj(self, fileobj):
""""Set the file object to write the download to. """"Set the file object to write the download to.

View File

@ -23,6 +23,7 @@ import functools
import io import io
import os import os
import re import re
import sys
import collections import collections
import uuid import uuid
import email.policy import email.policy
@ -32,7 +33,7 @@ import email.mime.multipart
from PyQt5.QtCore import QUrl from PyQt5.QtCore import QUrl
from qutebrowser.browser import webelem from qutebrowser.browser import webelem, downloads
from qutebrowser.utils import log, objreg, message, usertypes, utils, urlutils from qutebrowser.utils import log, objreg, message, usertypes, utils, urlutils
try: try:
@ -373,7 +374,7 @@ class _Downloader():
log.downloads.debug("Oops! Download already gone: %s", item) log.downloads.debug("Oops! Download already gone: %s", item)
return return
item.fileobj.actual_close() item.fileobj.actual_close()
self.writer.add_file(ulrutils.encoded_url(url), b'') self.writer.add_file(urlutils.encoded_url(url), b'')
if self.pending_downloads: if self.pending_downloads:
return return
self.finish_file() self.finish_file()
@ -428,12 +429,11 @@ def _start_download(dest, win_id, tab_id):
dest: The filename where the resulting file should be saved. dest: The filename where the resulting file should be saved.
win_id, tab_id: Specify the tab whose page should be loaded. win_id, tab_id: Specify the tab whose page should be loaded.
""" """
dest = os.path.expanduser(dest)
web_view = objreg.get('webview', scope='tab', window=win_id, tab=tab_id) web_view = objreg.get('webview', scope='tab', window=win_id, tab=tab_id)
loader = _Downloader(web_view, dest) loader = _Downloader(web_view, dest)
loader.run() loader.run()
def start_download_checked(dest, win_id, tab_id): def start_download_checked(dest, win_id, tab_id):
"""First check if dest is already a file, then start the download. """First check if dest is already a file, then start the download.
@ -441,20 +441,37 @@ def start_download_checked(dest, win_id, tab_id):
dest: The filename where the resulting file should be saved. dest: The filename where the resulting file should be saved.
win_id, tab_id: Specify the tab whose page should be loaded. win_id, tab_id: Specify the tab whose page should be loaded.
""" """
# start_download will call os.path.expanduser on dest too, so no need to # The default name is 'page title.mht'
# overwrite dest. We just want to make sure that we're checking title = (objreg.get('webview', scope='tab', window=win_id, tab=tab_id)
# the right path here. This also means that the user question will show the .title())
# original path, not the expanded. default_name = title + '.mht'
if not os.path.isfile(os.path.expanduser(dest)):
_start_download(dest, win_id=win_id, tab_id=tab_id) # Remove characters which cannot be expressed in the file system encoding
encoding = sys.getfilesystemencoding()
default_name = utils.force_encoding(default_name, encoding)
dest = utils.force_encoding(dest, encoding)
dest = os.path.expanduser(dest)
# See if we already have an absolute path
path = downloads.create_full_filename(default_name, dest)
if path is None:
# We still only have a relative path, prepend download_dir and
# try again.
path = downloads.create_full_filename(
default_name, os.path.join(downloads.download_dir(), dest))
downloads.last_used_directory = os.path.dirname(path)
if not os.path.isfile(path):
_start_download(path, win_id=win_id, tab_id=tab_id)
return return
q = usertypes.Question() q = usertypes.Question()
q.mode = usertypes.PromptMode.yesno q.mode = usertypes.PromptMode.yesno
q.text = "{} exists. Overwrite?".format(dest) q.text = "{} exists. Overwrite?".format(path)
q.completed.connect(q.deleteLater) q.completed.connect(q.deleteLater)
q.answered_yes.connect(functools.partial( q.answered_yes.connect(functools.partial(
_start_download, dest, win_id=win_id, tab_id=tab_id)) _start_download, path, win_id=win_id, tab_id=tab_id))
message_bridge = objreg.get('message-bridge', scope='window', message_bridge = objreg.get('message-bridge', scope='window',
window=win_id) window=win_id)
message_bridge.ask(q, blocking=False) message_bridge.ask(q, blocking=False)