qutebrowser/qutebrowser/browser/webengine/webenginedownloads.py
2016-11-04 18:49:24 +01:00

132 lines
4.8 KiB
Python

# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
# qutebrowser 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 3 of the License, or
# (at your option) any later version.
#
# qutebrowser 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 qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""QtWebEngine specific code for downloads."""
from PyQt5.QtCore import pyqtSlot, Qt
from PyQt5.QtWebEngineWidgets import QWebEngineDownloadItem
from PyQt5.QtWidgets import QApplication
from qutebrowser.browser import downloads
from qutebrowser.utils import debug, usertypes, message, log
class DownloadItem(downloads.AbstractDownloadItem):
"""A wrapper over a QWebEngineDownloadItem.
Attributes:
_qt_item: The wrapped item.
"""
def __init__(self, qt_item, parent=None):
super().__init__(parent)
self._qt_item = qt_item
qt_item.downloadProgress.connect(self.stats.on_download_progress)
qt_item.stateChanged.connect(self._on_state_changed)
@pyqtSlot(QWebEngineDownloadItem.DownloadState)
def _on_state_changed(self, state):
state_name = debug.qenum_key(QWebEngineDownloadItem, state)
log.downloads.debug("State for {!r} changed to {}".format(
self, state_name))
if state == QWebEngineDownloadItem.DownloadRequested:
pass
elif state == QWebEngineDownloadItem.DownloadInProgress:
pass
elif state == QWebEngineDownloadItem.DownloadCompleted:
self.successful = True
self.done = True
self.finished.emit()
elif state == QWebEngineDownloadItem.DownloadCancelled:
self.successful = False
self.done = True
self.cancelled.emit()
elif state == QWebEngineDownloadItem.DownloadInterrupted:
self.successful = False
self.done = True
# https://bugreports.qt.io/browse/QTBUG-56839
self.error.emit("Download failed")
else:
raise ValueError("_on_state_changed was called with unknown state "
"{}".format(state_name))
def _do_die(self):
self._qt_item.downloadProgress.disconnect()
self._qt_item.cancel()
def _do_cancel(self):
self._qt_item.cancel()
def retry(self):
# https://bugreports.qt.io/browse/QTBUG-56840
raise downloads.UnsupportedOperationError
def get_open_filename(self):
return self._filename
def _set_fileobj(self, fileobj):
self._set_filename(fileobj.name)
def _ensure_can_set_filename(self, filename):
state = self._qt_item.state()
if state != QWebEngineDownloadItem.DownloadRequested:
state_name = debug.qenum_key(QWebEngineDownloadItem, state)
raise ValueError("Trying to set filename {} on {!r} which is state "
"{} (not in requested state)!".format(
filename, self, state_name))
def _after_set_filename(self):
self._qt_item.setPath(self._filename)
self._qt_item.accept()
class DownloadManager(downloads.AbstractDownloadManager):
"""Manager for currently running downloads."""
def install(self, profile):
"""Set up the download manager on a QWebEngineProfile."""
profile.downloadRequested.connect(self.handle_download,
Qt.DirectConnection)
@pyqtSlot(QWebEngineDownloadItem)
def handle_download(self, qt_item):
download = DownloadItem(qt_item)
self._init_item(download, auto_remove=False,
suggested_filename=qt_item.path())
filename = downloads.immediate_download_path()
if filename is not None:
# User doesn't want to be asked, so just use the download_dir
target = usertypes.FileDownloadTarget(filename)
download.set_target(target)
return
# Ask the user for a filename - needs to be blocking!
question = downloads.get_filename_question(
suggested_filename=qt_item.path(), url=qt_item.url(),
parent=self)
self._init_filename_question(question, download)
message.global_bridge.ask(question, blocking=True)
# The filename is set via the question.answered signal, connected in
# _init_filename_question.